Maison >développement back-end >Tutoriel Python >Comment Python construit une blockchain
Blockchain est un grand livre (base de données distribuée) qui partage des données entre les nœuds d'un réseau informatique. En tant que base de données, la blockchain stocke les informations sous format électronique. L’innovation de la blockchain est qu’elle garantit la sécurité, l’authenticité et la crédibilité des enregistrements de données (sans avoir recours à un tiers de confiance).
La différence entre la blockchain et les bases de données classiques réside dans la structure des données. La blockchain collecte des informations sous forme de bloc
. block
的方式收集信息。
block
是一种能永久记录加密货币交易数据(或其他用途)的一种数据结构。类似于链表。一个block
记录了一些火所有尚未被验证的最新交易。验证数据后,block
将关闭,之后会创建一个新的block
来输入和验证新的交易。因此,一旦写入,永久不能更改和删除。
block
是区块链中存储和加密信息的地方
block
由长数字标识,其中包括先前加密块的加密交易信息和新的交易信息
在创建之前,block
以及其中的信息必须由网络验证
以下是一个简单的例子:
block = { 'index': 1, 'timestamp': 1506057125.900785, 'transactions': [ { 'sender': "8527147fe1f5426f9dd545de4b27ee00", 'recipient': "a77f5cdfa2934df3954a5c7c7da5df1f", 'amount': 5, } ], 'proof': 324984774000, 'previous_hash': "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" }
区块链的目标是允许数字信息被记录和分发,但不能编辑。通过这种方式,区块链成为了不可变分类账或无法更改、删除和销毁的交易记录的基础。
想象一下,一家公司拥有10000台服务器,用于维护一个包含所有客户信息的数据库。公司的所有服务器都在一个仓库中,可以完全控制每台服务器。这就提供了单点故障。如果那个地方停电了怎么办?如果他的网络连接被切断了怎么办?在任何情况下,数据都会丢失或损坏。
我们将创建一个BlockChain
类,构造函数创建一个空列表来存储区块链,再创建一个空列表来存储交易。创建block_chain.py
# block_chain.py class Blockchain: def __init__(self) -> None: self.chain = [] self.current_transactions = [] def new_block(self): # Creates a new Block and adds it to the chain pass def new_transaction(self): # Adds a new transaction to the list of transactions pass @staticmethod def hash(block): # Hashes a Block pass @property def last_block(self): # Returns the last Block in the chain pass
我们需要一种将交易添加到区块的方法。new_transaction
负责这个
class Blockchain(object): ... def new_transaction(self, sender, recipient, amount) -> int: self.current_transactions.append({ 'sender': sender, 'recipient': recipient, 'amount': amount, }) return self.last_block['index'] + 1
在 new_transaction
将交易添加到列表后,它返回交易将被添加到的块的索引——下一个要挖掘的块。这将在以后对提交交易的用户有用。
当我们的区块链被实例化时,我们需要为它播种一个创世块——一个没有前辈的块。我们还需要向我们的创世块添加一个“证明”,这是挖掘的结果(或工作量证明)。除了在我们的构造函数中创建创世块之外,我们还将充实 new_block()、new_transaction() 和 hash() 的方法:
import hashlib import json from time import time class Blockchain: def __init__(self) -> None: self.chain = [] self.current_transactions = [] # Create the genesis block self.new_block(previous_hash=1, proof=100) def new_block(self, proof, previous_hash=None) -> dict: block = { 'index': len(self.chain) + 1, 'timestamp': time(), 'transactions': self.current_transactions, 'proof': proof, 'previous_hash': previous_hash or self.hash(self.chain[-1]), } self.current_transactions = [] self.chain.append(block) return block def new_transaction(self, sender, recipient, amount) -> int: self.current_transactions.append( { 'sender': sender, 'recipient': recipient, 'amount': amount, } ) return self.last_block['index'] + 1 @property def last_block(self) -> dict: # Returns the last Block in the chain return self.chain[-1] @staticmethod def hash(block) -> str: block_string = json.dumps(block, sort_keys=True).encode() return hashlib.sha256(block_string).hexdigest()
到这里,我们几乎完成了代表我们的区块链。但此时,你一定想知道新区块是如何创建、锻造或开采的。
工作量证明算法 (PoW) 是在区块链上创建或挖掘新块的方式,它的目标是发现一个解决问题的数字。这个数字必须很难找到但很容易被网络上的任何人验证。PoW广泛用于加密货币挖掘,用于验证交易和挖掘新代币。由于PoW,比特币和其他加密货币交易可以以安全的方式进行点对点处理,而无需受信任的第三方。
让我们实现一个类似的算法:
class Blockchain(object): def proof_of_work(self, last_proof) -> int: proof = 0 while self.valid_proof(last_proof, proof) is False: proof += 1 return proof @staticmethod def valid_proof(last_proof, proof) -> bool: guess = f'{last_proof}{proof}'.encode() guess_hash = hashlib.sha256(guess).hexdigest() return guess_hash[:4] == '0000'
为了使区块链能够交互,我们需要一个将其置于web服务器上。这里我们是用Flask
框架。
如果没有安装,需要安装flask
pip install flask
我们的服务器将在我们的区块链网络中形成单一节点,在同级目录下创建一个app.py
block
est une structure de données qui peut enregistrer en permanence les données de transaction de crypto-monnaie (ou à d'autres fins). Semblable à une liste chaînée. Un bloc
enregistre toutes les dernières transactions qui n'ont pas encore été vérifiées. Après avoir vérifié les données, le bloc
sera fermé et un nouveau bloc
sera créé pour saisir et vérifier de nouvelles transactions. Par conséquent, une fois rédigé, il ne peut être modifié ou supprimé définitivement.
block
est l'endroit où les informations sont stockées et cryptées dans la blockchain
block
code> Identifié par un numéro long qui comprend les informations de transaction cryptées du bloc précédemment crypté et les informations de la nouvelle transaction
bloc
et les informations qu'il contient doivent être déterminé par le réseau Vérification
from uuid import uuid4 from time import time from textwrap import dedent from flask import Flask, jsonify, request from block_chain import Blockchain # 实例化应用 app = Flask(__name__) # 创建随机节点名称 node_identifier = str(uuid4()).replace('_', '') # 实例化block_chain类 block_chain = Blockchain() # 创建/mine端点 @app.route('/mine', methods=['GET']) def mine(): block_chain.new_transaction( sender="0", recipient=node_identifier, amount=1, ) last_block = block_chain.last_block last_proof = last_block['proof'] proof = block_chain.proof_of_work(last_proof) previous_hash = block_chain.hash(last_block) block = block_chain.new_block(proof, previous_hash) 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('/transactions/new', methods=['POST']) def new_transaction(): return "We'll add a new transaction" @app.route('/chain', methods=['GET']) def full_chain(): response = { 'chain': block_chain.chain, 'length': len(block_chain.chain), } return jsonify(response), 200 # 修改端口号 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
Objectif
Le but de la blockchain est de permettre l'enregistrement et la distribution d'informations numériques, mais non modifiables. De cette manière, la blockchain devient la base d’un grand livre immuable, ou d’un enregistrement de transactions qui ne peut être modifié, supprimé ou détruit. DécentralisationImaginez une entreprise avec 10 000 serveurs gérant une base de données contenant toutes les informations client. Tous les serveurs de l'entreprise se trouvent dans un seul entrepôt, avec un contrôle total sur chaque serveur. Cela fournit un point de défaillance unique. Et si le courant était coupé à cet endroit ? Et si sa connexion internet est coupée ? Dans tous les cas, les données peuvent être perdues ou corrompues. BuildingClasse Blockchain🎜🎜Nous allons créer une classeBlockChain
, le constructeur crée une liste vide pour stocker la blockchain, puis crée une liste vide pour stocker les transactions. Créez block_chain.py
🎜... from urllib.parse import urlparse ... class Blockchain: def __init__(self) -> None: ... self.nodes = set() ... def register_node(self, address) -> None: parsed_url = urlparse(address) self.nodes.add(parsed_url.netloc)🎜Ajouter des transactions🎜🎜Nous avons besoin d'un moyen d'ajouter des transactions au bloc.
new_transaction
en est responsable 🎜... import requests class Blockchain: ... def valid_chain(self, chain): last_block = chain[0] current_index = 1 while current_index < len(chain): block = chain[current_index] print(f'{last_block}') print(f'{block}') print("\n-----------\n") # Check that the hash of the block is correct if block['previous_hash'] != self.hash(last_block): return False # Check that the Proof of Work is correct if not self.valid_proof(last_block['proof'], block['proof']): return False last_block = block current_index += 1 return True def resolve_conflicts(self): """ This is our Consensus Algorithm, it resolves conflicts by replacing our chain with the longest one in the network. :return: <bool> True if our chain was replaced, False if not """ neighbours = self.nodes new_chain = None # We're only looking for chains longer than ours max_length = len(self.chain) # Grab and verify the chains from all the nodes in our network for node in neighbours: response = requests.get(f'http://{node}/chain') if response.status_code == 200: length = response.json()['length'] chain = response.json()['chain'] # Check if the length is longer and the chain is valid if length > max_length and self.valid_chain(chain): max_length = length new_chain = chain # Replace our chain if we discovered a new, valid chain longer than ours if new_chain: self.chain = new_chain return True return False🎜Après que
new_transaction
ait ajouté la transaction à la liste, il renvoie l'index du bloc auquel la transaction sera ajoutée - le prochain bloc à être extrait. Cela sera utile plus tard à l'utilisateur qui a soumis la transaction. 🎜🎜Créer de nouveaux blocs🎜🎜Lorsque notre blockchain est instanciée, nous devons l'ensemencer avec un bloc Genesis - un bloc sans prédécesseurs. Nous devons également ajouter une « preuve » à notre bloc Genesis, qui est le résultat du minage (ou preuve de travail). En plus de créer le bloc Genesis dans notre constructeur, nous étofferons également les méthodes new_block(), new_transaction() et hash() : 🎜@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🎜À ce stade, nous avons presque fini de représenter notre blockchain. Mais à ce stade, vous devez vous demander comment les nouveaux blocs sont créés, forgés ou extraits. 🎜🎜POW🎜🎜Proof-of-Work (PoW) est un moyen de créer ou d'exploiter de nouveaux blocs sur une blockchain dans le but de découvrir un nombre qui résout un problème. Ce numéro doit être difficile à trouver mais facilement vérifiable par n'importe qui sur le Web. PoW est largement utilisé dans l’extraction de crypto-monnaie pour valider les transactions et extraire de nouvelles pièces. Grâce à PoW, les transactions Bitcoin et autres cryptomonnaies peuvent être traitées en peer-to-peer de manière sécurisée sans avoir recours à un tiers de confiance. 🎜🎜Implémentons un algorithme similaire : 🎜rrreee🎜API🎜🎜Pour que la blockchain puisse interagir, nous avons besoin d'un moyen de la mettre sur un serveur Web. Ici, nous utilisons le framework
Flask
. 🎜🎜S'il n'est pas installé, vous devez installer flask
🎜🎜🎜pip install flask🎜🎜🎜Notre serveur formera un nœud unique dans notre réseau blockchain, créera un dans le même répertoire >app.py
:🎜rrreee🎜Ensuite, exécutez🎜🎜🎜flask run🎜🎜🎜Envoyez la demande via le logiciel API (cette fois en utilisant api fox) :🎜🎜🎜🎜🎜🎜🎜🎜Enregistrez un nouveau nœud🎜 🎜Tout l’intérêt des blockchains est qu’elles doivent être décentralisées. Si vous souhaitez avoir plusieurs nœuds dans le réseau, vous devez utiliser un algorithme de consensus. Avant de pouvoir implémenter un algorithme de consensus, nous avons besoin d’un moyen permettant aux nœuds de connaître leurs nœuds voisins sur le réseau. Chaque nœud de notre réseau doit maintenir un registre des autres nœuds du réseau. Par conséquent, nous avons besoin de plus de points de terminaison : 🎜rrreee🎜Conflits🎜🎜Un conflit se produit lorsqu'un nœud a une chaîne différente de celle d'un autre nœud. Pour résoudre ce problème, nous développerons la règle selon laquelle la chaîne valide la plus longue est l’autorité. Grâce à cet algorithme, nous parvenons à un consensus entre les nœuds du réseau. 🎜... import requests class Blockchain: ... def valid_chain(self, chain): last_block = chain[0] current_index = 1 while current_index < len(chain): block = chain[current_index] print(f'{last_block}') print(f'{block}') print("\n-----------\n") # Check that the hash of the block is correct if block['previous_hash'] != self.hash(last_block): return False # Check that the Proof of Work is correct if not self.valid_proof(last_block['proof'], block['proof']): return False last_block = block current_index += 1 return True def resolve_conflicts(self): """ This is our Consensus Algorithm, it resolves conflicts by replacing our chain with the longest one in the network. :return: <bool> True if our chain was replaced, False if not """ neighbours = self.nodes new_chain = None # We're only looking for chains longer than ours max_length = len(self.chain) # Grab and verify the chains from all the nodes in our network for node in neighbours: response = requests.get(f'http://{node}/chain') if response.status_code == 200: length = response.json()['length'] chain = response.json()['chain'] # Check if the length is longer and the chain is valid if length > max_length and self.valid_chain(chain): max_length = length new_chain = chain # Replace our chain if we discovered a new, valid chain longer than ours if new_chain: self.chain = new_chain return True return False
第一个方法 valid_chain() 负责通过遍历每个块并验证哈希和证明来检查链是否有效。resolve_conflicts() 是一种循环遍历我们所有相邻节点、下载它们的链并使用上述方法验证它们的方法。如果找到一个有效的链,其长度大于我们的,我们将替换我们的。
让我们将两个端点注册到我们的 API,一个用于添加相邻节点,另一个用于解决冲突:
@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
在这一点上,如果你愿意,你可以拿一台不同的机器,并在你的网络上启动不同的节点。或者在同一台机器上使用不同的端口启动进程。比如创建两个端口5000和6000来进行尝试。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!