区块链原理的实现(Python)

区块结构

区块链原理的实现(Python)_第1张图片

一个块应该包含的信息:
块的索引
时间戳
交易信息  

   一个数组,包含交易的发送者、接收者、交易的金额
工作量证明
上一个区块的哈希值

 

 

实现区块类结构

# {
#     "index":0,
#     "timestamp":"",
#     "transactions":[
#         {
#         "sender":"",
#         "recipient":"",
#         "amount":5,
#         }
#     ],
#     "proof":"",
#     "previous_hash":""
# }



class Blockchain:

    def __init__(self):
        self.chain = []     #数组中的元素都是一个个区块
        self.current_transations = []  #保存当前的交易信息

    def new_block(self):    #新添加一个块
        pass

    def new_transaction(self):    #新添加交易
        pass

    @staticmethod
    def hash(block):  #计算区块的哈希值
        pass

    @property
    def last_block(self): #获取区块中的最后一个块
        pass

 

添加交易

# {
#     "index":0,
#     "timestamp":"",
#     "transactions":[
#         {
#         "sender":"",
#         "recipient":"",
#         "amount":5,
#         }
#     ],
#     "proof":"",
#     "previous_hash":""
# }



class Blockchain:

    def __init__(self):
        self.chain = []     #数组中的元素都是一个个区块
        self.current_transations = []  #保存当前的交易信息

    def new_block(self):    #新添加一个块
        pass

    def new_transaction(self,sender,recipient,amount) -> int:    #新添加交易
        self.current_transations.append(
            {
                'sender':sender,
                'recipient':recipient,
                'amount':amount
            }
        )

        return self.last_block['index'] + 1

    @staticmethod
    def hash(block):  #计算区块的哈希值
        pass

    @property
    def last_block(self): #获取区块中的最后一个块
        pass

 

实现创建区块

# {
#     "index":0,
#     "timestamp":"",
#     "transactions":[
#         {
#         "sender":"",
#         "recipient":"",
#         "amount":5,
#         }
#     ],
#     "proof":"",
#     "previous_hash":""
# }
import hashlib
import json
from time import time
from typing import Any, Dict, List, Optional
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_transations = []  #保存当前的交易信息
        #创世纪的区块
        self.new_block(proof=100, previous_hash=1)

    def new_block(self,proof,previous_hash):    #新添加一个块
        block = {
            'index':len(self.chain) + 1,
            'timestamp':time(),
            'transcations': self.current_transationsm,
            'proof':proof,
            'previous_hash':previous_hash or self.hash(self.self_block)
        }

        #交易已经打包成区块了,把当前的交易清空
        self.current_transations = []
        self.chain.append(block)

        return block


    def new_transaction(self,sender,recipient,amount) -> int:    #新添加交易
        self.current_transations.append(
            {
                'sender':sender,
                'recipient':recipient,
                'amount':amount
            }
        )

        return self.last_block['index'] + 1

    @staticmethod
    def hash(block):  #计算区块的哈希值
        #把block转换成字节数组
        block_string = json.dumps(block,sorted_keys=True)
        hashlib.sha256(block_string).hexdigest()


    @property
    def last_block(self): #获取区块中的最后一个块
        return self.chain(-1)

 

实现工作量证明

是否满足以4个0开头

import hashlib
import json
from time import time
from typing import Any, Dict, List, Optional
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_transations = []  #保存当前的交易信息
        #创世纪的区块
        self.new_block(proof=100, previous_hash=1)

    def new_block(self,proof,previous_hash):    #新添加一个块
        block = {
            'index':len(self.chain) + 1,
            'timestamp':time(),
            'transcations': self.current_transations,
            'proof':proof,
            'previous_hash':previous_hash or self.hash(self.self_block)
        }

        #交易已经打包成区块了,把当前的交易清空
        self.current_transations = []
        self.chain.append(block)

        return block


    def new_transaction(self,sender,recipient,amount) -> int:    #新添加交易
        self.current_transations.append(
            {
                'sender':sender,
                'recipient':recipient,
                'amount':amount
            }
        )

        return self.last_block['index'] + 1

    @staticmethod
    def hash(block):  #计算区块的哈希值
        #把block转换成字节数组
        block_string = json.dumps(block,sorted_keys=True)
        hashlib.sha256(block_string).hexdigest()


    @property
    def last_block(self): #获取区块中的最后一个块
        return self.chain(-1)


    def proof_of_work(self, last_proof:int) -> int:
        proof = 0
        while self.valid_proof(last_proof, proof) is False:
            proof += 1

        print(proof)
        return proof


    def valid_proof(self, last_proof: int, proof:int) -> bool:
        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()

        print(guess_hash)
        if guess_hash[0:4] == '0000':
            return True
        else:
            return False


if __name__ == '__main__':
    testPow = Blockchain()
    testPow.proof_of_work(100)

 

添加节点通信功能

通过Flask

import hashlib
import json
from time import time
from typing import Any, Dict, List, Optional
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_transations = []  #保存当前的交易信息
        #创世纪的区块
        self.new_block(proof=100, previous_hash=1)

    def new_block(self,proof,previous_hash):    #新添加一个块
        block = {
            'index':len(self.chain) + 1,
            'timestamp':time(),
            'transcations': self.current_transations,
            'proof':proof,
            'previous_hash':previous_hash or self.hash(self.self_block)
        }

        #交易已经打包成区块了,把当前的交易清空
        self.current_transations = []
        self.chain.append(block)

        return block


    def new_transaction(self,sender,recipient,amount) -> int:    #新添加交易
        self.current_transations.append(
            {
                'sender':sender,
                'recipient':recipient,
                'amount':amount
            }
        )

        return self.last_block['index'] + 1

    @staticmethod
    def hash(block):  #计算区块的哈希值
        #把block转换成字节数组
        block_string = json.dumps(block,sorted_keys=True)
        hashlib.sha256(block_string).hexdigest()


    @property
    def last_block(self): #获取区块中的最后一个块
        return self.chain(-1)


    def proof_of_work(self, last_proof:int) -> int:
        proof = 0
        while self.valid_proof(last_proof, proof) is False:
            proof += 1

        print(proof)
        return proof


    def valid_proof(self, last_proof: int, proof:int) -> bool:
        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()

        print(guess_hash)
        if guess_hash[0:4] == '0000':
            return True
        else:
            return False



app = Flask(__name__)

@app.route('/index',methods=['GET'])
def index():
    return 'Hello BlockChain'

@app.route('/transactions/new',methods=['POST'])
def new_transction():
    return "We'll add a new transctions"


@app.route('/mine',methods=['GET'])
def mine():
    return "We'll mine a new block"

@app.route('/chain', methods=['GET'])
def full_chain():
    return 'retutn full chain'


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

区块链原理的实现(Python)_第2张图片

区块链原理的实现(Python)_第3张图片

区块链原理的实现(Python)_第4张图片

 

交易接口实现

就是实现以下上面定义的几个flask函数

import hashlib
import json
from time import time
from typing import Any, Dict, List, Optional
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_transations = []  #保存当前的交易信息
        #创世纪的区块
        self.new_block(proof=100, previous_hash=1)

    def new_block(self,proof,previous_hash):    #新添加一个块
        block = {
            'index':len(self.chain) + 1,
            'timestamp':time(),
            'transcations': self.current_transations,
            'proof':proof,
            'previous_hash':previous_hash or self.hash(self.self_block)
        }

        #交易已经打包成区块了,把当前的交易清空
        self.current_transations = []
        self.chain.append(block)

        return block


    def new_transaction(self,sender,recipient,amount) -> int:    #新添加交易
        self.current_transations.append(
            {
                'sender':sender,
                'recipient':recipient,
                'amount':amount
            }
        )

        return self.last_block['index'] + 1

    @staticmethod
    def hash(block):  #计算区块的哈希值
        #把block转换成字节数组
        block_string = json.dumps(block,sorted_keys=True)
        hashlib.sha256(block_string).hexdigest()


    @property
    def last_block(self): #获取区块中的最后一个块
        return self.chain[-1]


    def proof_of_work(self, last_proof:int) -> int:
        proof = 0
        while self.valid_proof(last_proof, proof) is False:
            proof += 1

        print(proof)
        return proof


    def valid_proof(self, last_proof: int, proof:int) -> bool:
        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()

        print(guess_hash)
        if guess_hash[0:4] == '0000':
            return True
        else:
            return False



app = Flask(__name__)
blockchain = Blockchain()

@app.route('/index',methods=['GET'])
def index():
    return 'Hello BlockChain'

@app.route('/transactions/new',methods=['POST'])
def new_transction():
    values = request.get_json()
    required = ['sender', 'recipient','amount']

    if values is None:
        return 'Missing values', 400
    if not all (k in values for k in required):
        return "Missing values", 400
    index = blockchain.new_transaction(values['sender'],
                                       values['recipient'],
                                       values['amount'])
    response = {"message":f'Transcation will be added to Block {index}'}

    return jsonify(response), 201


@app.route('/mine',methods=['GET'])
def mine():
    return "We'll mine a new block"

@app.route('/chain', methods=['GET'])
def full_chain():
    response = {
        'chain':blockchain.chain,
        'length': len(blockchain.chain)

    }
    return jsonify(response),200


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

 

区块链原理的实现(Python)_第5张图片

区块链原理的实现(Python)_第6张图片

区块链原理的实现(Python)_第7张图片第一块是创始块,所以是第二块

 

挖矿接口实现

import hashlib
import json
from time import time
from typing import Any, Dict, List, Optional
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_transations = []  #保存当前的交易信息
        #创世纪的区块
        self.new_block(proof=100, previous_hash=1)

    def new_block(self,proof,previous_hash):    #新添加一个块
        block = {
            'index':len(self.chain) + 1,
            'timestamp':time(),
            'transactions': self.current_transations,
            'proof':proof,
            'previous_hash':previous_hash or self.hash(self.chain[-1])
        }

        #交易已经打包成区块了,把当前的交易清空
        self.current_transations = []
        self.chain.append(block)

        return block


    def new_transaction(self,sender,recipient,amount) -> int:    #新添加交易
        self.current_transations.append(
            {
                'sender':sender,
                'recipient':recipient,
                'amount':amount
            }
        )

        return self.last_block['index'] + 1

    @staticmethod
    def hash(block):  #计算区块的哈希值
        #把block转换成字节数组
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()


    @property
    def last_block(self): #获取区块中的最后一个块
        return self.chain[-1]


    def proof_of_work(self, last_proof:int) -> int:
        proof = 0
        while self.valid_proof(last_proof, proof) is False:
            proof += 1

        # print(proof)
        return proof


    def valid_proof(self, last_proof: int, proof:int) -> bool:
        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()

        # print(guess_hash)
        if guess_hash[0:4] == '0000':
            return True
        else:
            return False



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_transction():
    values = request.get_json()
    required = ['sender', 'recipient','amount']

    if values is None:
        return 'Missing values', 400
    if not all (k in values for k in required):
        return "Missing values", 400
    index = blockchain.new_transaction(values['sender'],
                                       values['recipient'],
                                       values['amount'])
    response = {"message":f'Transcation will be added to Block {index}'}

    return jsonify(response), 201


@app.route('/mine',methods=['GET'])
def mine():
    #先算块的工作量证明,然后给自己添加奖励交易
    last_block = blockchain.last_block
    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)
    
    response = {
        "message": "New Block Forged",
        "index": block['index'],
        "transactions": block['transactions'],
        "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)

    }
    return jsonify(response),200


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

区块链原理的实现(Python)_第8张图片

区块链原理的实现(Python)_第9张图片成功挖了一个

区块链原理的实现(Python)_第10张图片返回所有区块信息

 

这样,一个单节点的区块链就实现了

 

实现注册节点

import hashlib
import json
from time import time
from typing import Any, Dict, List, Optional
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_transations = []  #保存当前的交易信息
        self.nodes = set()  #保存节点信息
        #创世纪的区块
        self.new_block(proof=100, previous_hash=1)

    def register_node(self, address:str):
        #http://127.0.0.1:5001
        parsed_url = urlparse(address)
        self.nodes.add(parsed_url.netloc)



    def new_block(self,proof,previous_hash):    #新添加一个块
        block = {
            'index':len(self.chain) + 1,
            'timestamp':time(),
            'transactions': self.current_transations,
            'proof':proof,
            'previous_hash':previous_hash or self.hash(self.chain[-1])
        }

        #交易已经打包成区块了,把当前的交易清空
        self.current_transations = []
        self.chain.append(block)

        return block


    def new_transaction(self,sender,recipient,amount) -> int:    #新添加交易
        self.current_transations.append(
            {
                'sender':sender,
                'recipient':recipient,
                'amount':amount
            }
        )

        return self.last_block['index'] + 1

    @staticmethod
    def hash(block):  #计算区块的哈希值
        #把block转换成字节数组
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()


    @property
    def last_block(self): #获取区块中的最后一个块
        return self.chain[-1]


    def proof_of_work(self, last_proof:int) -> int:
        proof = 0
        while self.valid_proof(last_proof, proof) is False:
            proof += 1

        # print(proof)
        return proof


    def valid_proof(self, last_proof: int, proof:int) -> bool:
        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()

        # print(guess_hash)
        if guess_hash[0:4] == '0000':
            return True
        else:
            return False



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_transction():
    values = request.get_json()
    required = ['sender', 'recipient','amount']

    if values is None:
        return 'Missing values', 400
    if not all (k in values for k in required):
        return "Missing values", 400
    index = blockchain.new_transaction(values['sender'],
                                       values['recipient'],
                                       values['amount'])
    response = {"message":f'Transcation will be added to Block {index}'}

    return jsonify(response), 201


@app.route('/mine',methods=['GET'])
def mine():
    #先算块的工作量证明,然后给自己添加奖励交易
    last_block = blockchain.last_block
    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)
    
    response = {
        "message": "New Block Forged",
        "index": block['index'],
        "transactions": block['transactions'],
        "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)

    }
    return jsonify(response),200


#{"nodes":["http://127.0.0.2:5000"]}
@app.route('/nodes/register',methods=['POST'])
def register_nodes():
    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


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

区块链原理的实现(Python)_第11张图片

区块链原理的实现(Python)_第12张图片

 

实现共识机制

import hashlib
import json
from time import time
from typing import Any, Dict, List, Optional
from urllib.parse import urlparse
from uuid import uuid4

import requests
from flask import Flask, jsonify, request
from argparse import ArgumentParser


class Blockchain:

    def __init__(self):
        self.chain = []     #数组中的元素都是一个个区块
        self.current_transations = []  #保存当前的交易信息
        self.nodes = set()  #保存节点信息
        #创世纪的区块
        self.new_block(proof=100, previous_hash=1)

    def register_node(self, address:str):
        #http://127.0.0.1:5001
        parsed_url = urlparse(address)
        self.nodes.add(parsed_url.netloc)

    def valid_chain(self, chain) -> bool:
        #判断依据就是看它的每个哈希值是否是上一个块的哈希
        last_block = chain[0]
        current_index = 1

        while current_index < len(chain):
            block = chain[current_index]

            if block['previous_hash'] != self.hash(last_block):
                return False

            if not self.valid_proof(last_block['proof'], block['proof']): #如果工作量证明不满足
                return False

            last_block = block
            current_index += 1

        return True


    def resolve_conflicts(self) -> bool:

        neighbours = self.nodes  #相邻的节点

        max_length = len(self.chain)
        new_chain = None

        for node in neighbours:
            response = requests.get(f'http://{node}/chain')#获取邻接节点的区块链信息
            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
                    new_chain = chain

        if new_chain:
            self.chain = new_chain
            return True

        return False


    def new_block(self,proof,previous_hash):    #新添加一个块
        block = {
            'index':len(self.chain) + 1,
            'timestamp':time(),
            'transactions': self.current_transations,
            'proof':proof,
            'previous_hash':previous_hash or self.hash(self.chain[-1])
        }

        #交易已经打包成区块了,把当前的交易清空
        self.current_transations = []
        self.chain.append(block)

        return block


    def new_transaction(self,sender,recipient,amount) -> int:    #新添加交易
        self.current_transations.append(
            {
                'sender':sender,
                'recipient':recipient,
                'amount':amount
            }
        )

        return self.last_block['index'] + 1

    @staticmethod
    def hash(block):  #计算区块的哈希值
        #把block转换成字节数组
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()


    @property
    def last_block(self): #获取区块中的最后一个块
        return self.chain[-1]


    def proof_of_work(self, last_proof:int) -> int:
        proof = 0
        while self.valid_proof(last_proof, proof) is False:
            proof += 1

        # print(proof)
        return proof


    def valid_proof(self, last_proof: int, proof:int) -> bool:
        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()

        # print(guess_hash)
        if guess_hash[0:4] == '0000':
            return True
        else:
            return False



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_transction():
    values = request.get_json()
    required = ['sender', 'recipient','amount']

    if values is None:
        return 'Missing values', 400
    if not all (k in values for k in required):
        return "Missing values", 400
    index = blockchain.new_transaction(values['sender'],
                                       values['recipient'],
                                       values['amount'])
    response = {"message":f'Transcation will be added to Block {index}'}

    return jsonify(response), 201


@app.route('/mine',methods=['GET'])
def mine():
    #先算块的工作量证明,然后给自己添加奖励交易
    last_block = blockchain.last_block
    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)
    
    response = {
        "message": "New Block Forged",
        "index": block['index'],
        "transactions": block['transactions'],
        "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)

    }
    return jsonify(response),200


#{"nodes":["http://127.0.0.2:5000"]}
@app.route('/nodes/register',methods=['POST'])
def register_nodes():
    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 consensus():
    replaced = blockchain.resolve_conflicts()

    if replaced:
        response = {
            "message": 'Our chain was replaced',
            'new_chain': blockchain.chain
        }
    else:
        response={
            'message': 'Our chain is authoritative',
            'chain': blockchain.chain
        }

    return jsonify(response),200


if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument('-p','--port',default=5051, type=int,help='port to listen to')
    args = parser.parse_args()
    port = args.port
    
    app.run(host='0.0.0.0', port=port)

区块链原理的实现(Python)_第13张图片

 

分别在5000和5001起两个终端

区块链原理的实现(Python)_第14张图片

区块链原理的实现(Python)_第15张图片

先看一下5000的链条

区块链原理的实现(Python)_第16张图片长度是1

然后我们给5000节点添加一个交易

区块链原理的实现(Python)_第17张图片

此时链条长度还是1,因为我们没有挖矿

请求挖矿

区块链原理的实现(Python)_第18张图片

此时看一下链条长度

区块链原理的实现(Python)_第19张图片长度是2

 

此时看一下5001节点的链条长度

区块链原理的实现(Python)_第20张图片长度是1

 

这个时候,就发生了节点5000和节点5001的长度是不一样的

按照共识机制,应该是采用5000节点的长度

然后现在我们把节点5000节点注册到5001上去,将5001节点注册到5000上

区块链原理的实现(Python)_第21张图片显示节点已添加

区块链原理的实现(Python)_第22张图片显示节点已添加

此时查看5001节点解决冲突的方法

区块链原理的实现(Python)_第23张图片链条已经被替换成长的

此时查看5001的链条长度

区块链原理的实现(Python)_第24张图片

 

至此,一个区块链的雏形就实现了

总的

blockchain.py

import hashlib
import json
from time import time
from typing import Any, Dict, List, Optional
from urllib.parse import urlparse
from uuid import uuid4

import requests
from flask import Flask, jsonify, request
from argparse import ArgumentParser


class Blockchain:

    def __init__(self):
        self.chain = []     #数组中的元素都是一个个区块
        self.current_transations = []  #保存当前的交易信息
        self.nodes = set()  #保存节点信息
        #创世纪的区块
        self.new_block(proof=100, previous_hash=1)

    def register_node(self, address:str):
        #http://127.0.0.1:5001
        parsed_url = urlparse(address)
        self.nodes.add(parsed_url.netloc)

    def valid_chain(self, chain) -> bool:
        #判断依据就是看它的每个哈希值是否是上一个块的哈希
        last_block = chain[0]
        current_index = 1

        while current_index < len(chain):
            block = chain[current_index]

            if block['previous_hash'] != self.hash(last_block):
                return False

            if not self.valid_proof(last_block['proof'], block['proof']): #如果工作量证明不满足
                return False

            last_block = block
            current_index += 1

        return True


    def resolve_conflicts(self) -> bool:

        neighbours = self.nodes  #相邻的节点

        max_length = len(self.chain)
        new_chain = None

        for node in neighbours:
            response = requests.get(f'http://{node}/chain')#获取邻接节点的区块链信息
            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
                    new_chain = chain

        if new_chain:
            self.chain = new_chain
            return True

        return False


    def new_block(self,proof,previous_hash):    #新添加一个块
        block = {
            'index':len(self.chain) + 1,
            'timestamp':time(),
            'transactions': self.current_transations,
            'proof':proof,
            'previous_hash':previous_hash or self.hash(self.chain[-1])
        }

        #交易已经打包成区块了,把当前的交易清空
        self.current_transations = []
        self.chain.append(block)

        return block


    def new_transaction(self,sender,recipient,amount) -> int:    #新添加交易
        self.current_transations.append(
            {
                'sender':sender,
                'recipient':recipient,
                'amount':amount
            }
        )

        return self.last_block['index'] + 1

    @staticmethod
    def hash(block):  #计算区块的哈希值
        #把block转换成字节数组
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()


    @property
    def last_block(self): #获取区块中的最后一个块
        return self.chain[-1]


    def proof_of_work(self, last_proof:int) -> int:
        proof = 0
        while self.valid_proof(last_proof, proof) is False:
            proof += 1

        # print(proof)
        return proof


    def valid_proof(self, last_proof: int, proof:int) -> bool:
        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()

        # print(guess_hash)
        if guess_hash[0:4] == '0000':
            return True
        else:
            return False



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_transction():
    values = request.get_json()
    required = ['sender', 'recipient','amount']

    if values is None:
        return 'Missing values', 400
    if not all (k in values for k in required):
        return "Missing values", 400
    index = blockchain.new_transaction(values['sender'],
                                       values['recipient'],
                                       values['amount'])
    response = {"message":f'Transcation will be added to Block {index}'}

    return jsonify(response), 201


@app.route('/mine',methods=['GET'])
def mine():
    #先算块的工作量证明,然后给自己添加奖励交易
    last_block = blockchain.last_block
    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)
    
    response = {
        "message": "New Block Forged",
        "index": block['index'],
        "transactions": block['transactions'],
        "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)

    }
    return jsonify(response),200


#{"nodes":["http://127.0.0.2:5000"]}
@app.route('/nodes/register',methods=['POST'])
def register_nodes():
    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 consensus():
    replaced = blockchain.resolve_conflicts()

    if replaced:
        response = {
            "message": 'Our chain was replaced',
            'new_chain': blockchain.chain
        }
    else:
        response={
            'message': 'Our chain is authoritative',
            'chain': blockchain.chain
        }

    return jsonify(response),200


if __name__ == '__main__':
    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)

 

你可能感兴趣的:(区块链,比特币,Python)