从代码的角度理解比特币和区块链原理

本贴最后更新于 1939 天前,其中的信息可能已经沧海桑田

1.前言

比特币和区块链技术是现在非常火的技术,但是我们对其的原理并没有深究,今天我们通过 python 代码来实现一个简单的区块链,通过代码来了解区块链技术

需要的工具和环境:

工具:
1. pycharm
2. postman

环境:
1. python3
2. flask
3. requests

环境和工具的安装和搭建不做赘述,不懂的可以自己 google 或者百度,下面我们进入正题

2.搭建区块链

2.1 初始化类和需要的属性

我们新建一个类并初始化区块链需要的数据类型, 一个 chain 数组来存放整个链,一个 transactions 来记录没有防区区块链中的交易,一个 nodes 来存放整个网络中的节点,初始化区块 new_block(创世块)

class Blockchain:

    def __init__(self):
        self.chain = []
        self.current_transactions = []

        self.nodes = set()

        self.new_block(proof=100, previous_hash=1)

2.2 创建一个新的块

新建一个区块并存放到 chain 数组里面,每一个块里面要有基本的数据

    def new_block(self, proof, previous_hash=None):
        block = {
            'index': len(self.chain) + 1, //block的坐标
            'timestamp': time(), //时间戳
            'transactions': self.current_transactions, //当前的所有交易
            'proof': proof,  //工作量证明
            'previous_hash': previous_hash or self.hash(self.last_block) //上一个数据的hash值
        }

        self.current_transactions = []
        self.chain.append(block)
        return block

2.3 新的交易记录

将新的交易记录到 current_transactions 中

    def new_transaction(self, sender, recipient, amount):
        self.current_transactions.append(
            {
                'sender': sender,
                'recipent': recipient,
                'amount': amount
            }
        )

        return self.last_block['index'] + 1

     @property
    def last_block(self):
        return self.chain[-1]

2.4 挖矿

挖矿是很关键的部分,他将当前所有的交易打包生成一个新的 block,加入区块链中,挖矿需要工作量证明,一般通过不断将上一个工作量证明加上一个自增的常数不断 hash 直到前几位等于规定的数字的时候才可以获取挖矿的权限,这需要大量的计算

    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)
        # sleep(1)
        return guess_hash[0:4] == "0000"

2.5 区块分岔

有的时候区块会分岔,这时候我们就需要验证区块,选择最长的一个有效的链为主链

    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):

                    new_chain = chain

        if new_chain:
            self.chain = new_chain
            return True
        return False

到此一个基本的区块链的核心就完毕了,我们下面加入 flask 通过 postman 来访问,来体验一下吧

运行区块链

加入 flask 之后完整的代码

import hashlib
import json
from argparse import ArgumentParser
from time import time
from urllib.parse import urlparse
from uuid import uuid4

import requests
from flask import Flask, app, jsonify, request


class Blockchain:

    def __init__(self):
        self.chain = []
        self.current_transactions = []

        self.nodes = set()

        self.new_block(proof=100, previous_hash=1)


    def register_node(self,address:str):
        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):

                    new_chain = chain

        if new_chain:
            self.chain = new_chain
            return True
        return False


    def new_block(self, proof, previous_hash=None):
        block = {
            'index': len(self.chain) + 1,
            'timestamp': time(),
            'transactions': self.current_transactions,
            'proof': proof,
            'previous_hash': previous_hash or self.hash(self.last_block)
        }

        self.current_transactions = []
        self.chain.append(block)
        return block

    def new_transaction(self, sender, recipient, amount):
        self.current_transactions.append(
            {
                'sender': sender,
                'recipent': recipient,
                'amount': amount
            }
        )

        return self.last_block['index'] + 1

    @staticmethod
    def hash(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)
        # sleep(1)
        return guess_hash[0:4] == "0000"


# testPow = Blockchain()
# testPow.proof_of_work(100)

app = Flask(__name__)

blockchain = Blockchain()
node_indentifier = str(uuid4()).replace('-', '')


@app.route("/transactions/new", methods=['POST'])
def new_transcation():
    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'Transacation will be added to Block {index}'}
    return jsonify(response), 200

@app.route("/nodes/register",methods=['POST'])
def register_nodes():
    values = request.get_json()
    nodes = values.get("nodes")
    if nodes is None:
        return "nodes not null",400

    for node in nodes:
        blockchain.register_node(node)

    response = {
        "message" : "node is add",
        "nodes" : list(blockchain.nodes)
    }

    return jsonify(response),200


@app.route("/mine", methods=['GET'])
def mine():
    last_block = blockchain.last_block

    proof_work = blockchain.proof_of_work(last_block['proof'])

    blockchain.new_transaction(
        sender="0",
        recipient=node_indentifier,
        amount=1
    )

    block = blockchain.new_block(proof_work, 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 chain():
    response = {
        'chain': blockchain.chain,
        'length': len(blockchain.chain)
    }
    return jsonify(response), 200

@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 chian is auth',
            'new_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)

postman 调用对应的连接

初始的区块链

新添加一个交易

挖矿

查看区块链,新的交易已经被打包成了一个新的区块

我们启动一个新的节点,加入区块链,并查看他的区块链

节点注册

节点数据同步,之后再查看区块链


我们发现数据已经同步,区块链的基本原理到这里就结束了,有兴趣的可以进一步研究

  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    91 引用 • 751 回帖
  • 比特币

    比特币(BitCoin)的概念最初由中本聪在 2009 年提出,根据中本聪的思路设计发布的开源软件以及建构其上的 P2P 网络。比特币是一种 P2P 形式的数字货币。点对点的传输意味着一个去中心化的支付系统。

    27 引用 • 169 回帖 • 79 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...