Cet article est le 6ème jour du Calendrier de l'Avent Blockchain 2019. Hier, c'était [Comprendre l'échange atomique] de @ y-chan (https://qiita.com/y-chan/items/f69b628f65ce12097e4a).
«Il existe de nombreux livres de commentaires sur la blockchain, mais je ne sais pas comment ils fonctionneront à la fin. "La blockchain structurelle semble facile, mais je ne sais pas comment créer le contenu du bloc ou comment le minage fonctionne."
je pensais "Si vous ne comprenez pas l'explication, vous devriez essayer de l'implémenter. C'est un programmeur de Mumuo." Alors je l'ai implémenté.
Le matériel pédagogique est de Gerald Nash
--Part.1 Construisons la plus petite blockchain (Faisons une très petite blockchain) --Part.2 Rendons la plus petite blockchain plus grande (Faisons une très petite blockchain)
est.
L'article de Gerald utilisé comme matériel pédagogique a été implémenté en Python2, il a donc été réimplémenté en Python3 (3.5). En passant, je corrige certaines parties telles que "N'est-ce pas le meilleur ordre de traitement?" Ou "Je ne vous appelle pas juste pour faire ça". Dans l'article d'origine, la partie import du code divisé a été omise, mais dans cet article, elle sera décrite dans le code qui fonctionne [^ 1]. De plus, les commentaires dans le code ne sont pas limités à l'article original et peuvent être ajoutés librement si nécessaire.
Tout le code source créé est décrit en supposant qu'il se trouve dans le même répertoire.
[^ 1]: Même dans l'article original, le code source en taille réelle est publié sur Gist, mais il y avait des choses comme "Vous ne l'utilisez pas, n'est-ce pas?", Donc je suis en train de le réparer.
――La gamme de "Faisons une toute petite blockchain" (environ 50 lignes)
Nous mettrons en œuvre dans l'ordre de. Le nombre total de lignes à l'exclusion des lignes de commentaires était d'environ 170.
Tout d'abord, implémentez le bloc. C'est une soi-disant unité minière. Les informations contenues sont
--Informations d'index
Sera.
snakecoin_block.py
import hashlib
class Block:
def __init__(self, index, timestamp, data, previous_hash):
self.index = index
self.timestamp = timestamp
self.data = data
self.previous_hash = previous_hash
self.hash = self.hashblock()
def hashblock(self):
sha = hashlib.sha256()
sha.update((str(self.index) +
str(self.timestamp) +
str(self.data) +
str(self.previous_hash)).encode('utf-8'))
return sha.hexdigest()
Étant donné que le bloc précédent est nécessaire pour générer une nouvelle blockchain, le premier bloc doit être stocké à l'avance. Il semble que cela s'appelle le bloc Genesis (bloc de création?).
Pour les données, la valeur minimale «9» calculée par l'algorithme PoW (Proof of Work) décrit plus loin est définie comme valeur de départ. De plus, puisque le hachage du bloc précédent n'existe pas, définissez `` 0 ''.
snakecoin_genesis.py
from snakecoin_block import Block
import datetime
def create_genesis_block():
return Block(0, datetime.datetime.now(), {
'message': 'Genesis Block',
'proof-of-work': 9
}, '0')
Afin de tester jusqu'à ce point, nous allons écrire un processus de test qui ajoute un bloc à la fin de la blockchain. Puisqu'il s'agit de tests, définissez une chaîne de caractères appropriée dans les données.
snakecoin_next_block.py
from snakecoin_block import Block
import datetime
def next_block(last_block):
this_index = last_block.index + 1
this_timestamp = datetime.datetime.now()
this_data = "Hey! I'm block " + str(this_index)
previous_hash = last_block.hash
return Block(this_index, this_timestamp, this_data, previous_hash)
Maintenant, la blockchain en tant que structure de données est terminée. Vérifions le fonctionnement en connectant ceux réalisés jusqu'à présent.
La procédure approximative est
est.
snakecoin_blockchain_test.py
from snakecoin_genesis import create_genesis_block
from snakecoin_next_block import next_block
#Créez un bloc Genesis pour créer une blockchain
blockchain = [create_genesis_block()]
#Bloc Genesis défini comme bloc d'extrémité
previous_block = blockchain[0]
#Nombre de blocs à connecter
num_of_blocks_to_add = 3
#Informations de sortie du bloc Genesis
print("Block #{} has been added to the blockchain!".format(previous_block.index))
print("Data: {}".format(previous_block.data))
print("PrHh: {}".format(previous_block.previous_hash))
print("Hash: {}\n".format(previous_block.hash))
for i in range(0, num_of_blocks_to_add):
#Créez un nouveau bloc et ajoutez-le à la blockchain
block_to_add = next_block(previous_block)
blockchain.append(block_to_add)
#Sortie de nouvelles informations de bloc
print("Block #{} has been added to the blockchain!".format(block_to_add.index))
print("Data: {}".format(block_to_add.data))
print("PrHh: {}".format(block_to_add.previous_hash))
print("Hash: {}\n".format(block_to_add.hash))
#Mettre à jour le bloc d'extrémité
previous_block = block_to_add
Une fois exécuté, le résultat suivant sera affiché. Le hachage «Hash» du propre bloc est enregistré dans le bloc suivant en tant que hachage «PrHh» du bloc précédent.
$ python snakecoin_blockchain_test.py
Block #0 has been added to the blockchain!
Data: {'proof-of-work': 9, 'message': 'Genesis Block'}
PrHh: 0
Hash: 96cab14611cd4e674d78bb2e3a93ccdf2364955575039d4ffa09a2714b12e8ac
Block #1 has been added to the blockchain!
Data: Hey! I'm block 1
PrHh: 96cab14611cd4e674d78bb2e3a93ccdf2364955575039d4ffa09a2714b12e8ac
Hash: 6023a093c0e3449692fe431679a3752a7201e74b17059087f777dfd54105f906
Block #2 has been added to the blockchain!
Data: Hey! I'm block 2
PrHh: 6023a093c0e3449692fe431679a3752a7201e74b17059087f777dfd54105f906
Hash: 18af14f5ab32bd40fa3c141290aba7a23cff058f391eb8769f4b5e4ea84aa0f8
Block #3 has been added to the blockchain!
Data: Hey! I'm block 3
PrHh: 18af14f5ab32bd40fa3c141290aba7a23cff058f391eb8769f4b5e4ea84aa0f8
Hash: 13ff0cbfcac15d705319e67abd48e3768fa6c4465ffe624689e65f29e91bf641
Maintenant, stockons réellement les informations de livraison dans la blockchain. Puisque REST est utilisé comme interface, nous le créerons en utilisant Flask.
Comme interface
--Enregistrement des transactions de livraison / transactions
--Bloquez les transactions et ajoutez-les à la blockchain / mines
--Blockchain référence / blocks
est.
Le comportement détaillé et le traitement qui peuvent être nécessaires pour le fonctionnement réel sont décrits dans le code sous forme de commentaires.
snakecoin_node_transaction.py
from snakecoin_block import Block
from snakecoin_genesis import create_genesis_block
from flask import Flask, request, jsonify
import datetime
import json
import requests
#Définir la blockchain
blockchain = []
blockchain.append(create_genesis_block())
#Liste des transactions
#Stocke les transactions dans ce nœud
this_nodes_tx = []
#Liste des URL de nœuds sur le réseau blockchain
# TODO:Créer un mécanisme pour détecter les nouveaux nœuds
peer_nodes = []
#L'adresse mineure est fixe pour le moment
# TODO:Créer un mécanisme pour générer et définir de manière unique chaque nœud
miner_address = "q3nf394hjg-random-miner-address-34nf3i4nflkn3oi"
#Algorithme de preuve de travail
#Dans BitCoin, etc., il s'agit d'une recherche de valeur de hachage pour des conditions spécifiques qui nécessite beaucoup de calcul.
#Ici pour la brièveté
#"Traitement * Le nombre de fois est divisible par 9" ET "Divisible par le résultat précédent"
#* Cette fois, c'est juste un incrément
#Est à découvrir.
#Cependant, dans cet état, le serveur exécute le processus de découverte.
#Le traitement n'est pas distribué et un branchement de la blockchain est susceptible de se produire.
# TODO:On suppose que la partie avec une grande quantité de calcul sera implémentée côté client, et seul le processus de confirmation sera implémenté côté serveur.
def proof_of_work(last_proof):
incrementor = last_proof + 1
while not (incrementor % 9 == 0 and incrementor % last_proof == 0):
incrementor += 1
return incrementor
#Obtenez les informations de la blockchain détenues par chaque nœud
def find_new_chains():
other_chains = []
for node_url in peer_nodes:
block = requests.get(node_url + '/blocks').content
block = json.reloads(block)
other_chains.append(block)
return other_chains
#Trouvez l'extrémité qui relie de nouveaux blocs
def consensus():
global blockchain
longest_chain = blockchain
#Obtenez des informations sur la blockchain détenues par d'autres nœuds
other_chains = find_new_chains()
#Recherchez la blockchain la plus longue et adoptez la plus longue blockchain.
#Si la blockchain est mise en œuvre en utilisant l'arrangement actuel, les informations sur les branches courtes de la blockchain branchée seront perdues.
# TODO:Changement de logique qui adopte l'extrémité la plus longue au lieu d'adopter la blockchain adoptée tout en conservant les branches branchées dans l'implémentation comme un graphe orienté
for chain in other_chains:
if len(longest_chain) < len(chain):
longest_chain = chain
blockchain = longest_chain
#### endpoints
node = Flask(__name__)
#Enregistrer une transaction de pass snakecoin
@node.route('/transactions', methods=['POST'])
def transactions():
if request.method == 'POST':
#Ajouter les données de transaction POSTÉES à la liste des transactions
new_tx = request.get_json()
this_nodes_tx.append(new_tx)
#Sortie standard des données de transaction ajoutées
print("New Transaction")
print("FROM: {}".format(new_tx['from']))
print("TO: {}".format(new_tx['to']))
print("AMOUNT: {}".format(new_tx['amount']))
return jsonify({'message': 'Transaction submission successful'}), 200
#Bloquer les transactions de passage et les connecter à la blockchain
@node.route('/mines', methods=['POST'])
def mines():
#Prendre le consensus
consensus()
#Obtenez la dernière preuve
last_block = blockchain[len(blockchain) - 1]
last_proof = last_block.data['proof-of-work']
#Exploitation minière
# TODO:Recevoir une nouvelle preuve en tant que paramètre et effectuer uniquement un jugement de conformité
proof = proof_of_work(last_proof)
#Ajout d'une transaction qui récompense les mineurs avec 1 snakecoin
this_nodes_tx.append({
"from": "network",
"to": miner_address,
"amount": 1
})
#Préparation des valeurs requises pour le nouveau bloc
#Ici, la liste des transactions est stockée dans un bloc
new_block_index = last_block.index + 1
new_block_timestamp = this_timestamp = datetime.datetime.now()
new_block_data = {
"proof-of-work": proof,
"transactions": list(this_nodes_tx)
}
last_block_hash = last_block.hash
#Générez un nouveau bloc et ajoutez-le à la blockchain
mined_block = Block(
new_block_index,
new_block_timestamp,
new_block_data,
last_block_hash
)
blockchain.append(mined_block)
#Initialiser la liste des transactions
this_nodes_tx[:] = []
return jsonify(
{
"index": new_block_index,
"timestamp": new_block_timestamp,
"data": new_block_data,
"hash": last_block_hash
}
)
#Reportez-vous aux informations de blockchain détenues par ce nœud
@node.route('/blocks', methods=['GET'])
def get_blocks():
chain_to_send = blockchain[:]
for i in range(len(chain_to_send)):
block = chain_to_send[i]
#Chaîne les propriétés de la classe Block
block_index = str(block.index)
block_timestamp = str(block.timestamp)
block_data = str(block.data)
block_hash = block.hash
#Convertir en type de dictionnaire afin qu'il puisse être converti en chaîne JSON
chain_to_send[i] = {
"index": block_index,
"timestamp": block_timestamp,
"data": block_data,
"hash": block_hash
}
#Convertir en chaîne JSON et retourner au client
return jsonify(chain_to_send)
node.run()
Dans l'article d'origine, cURL a été utilisé pour vérifier l'opération, donc dans cet article, je publierai le résultat de l'exécution de Postman.
$ python snakecoin_node_transaction.py
Lorsque vous démarrez avec et GET / blocks
, le contenu suivant sera renvoyé.
Une blockchain (arrangement) contenant des blocs Genesis a été renvoyée. Ensuite, enregistrons les informations de livraison de snakecoin avec POST / transactions
.
2 La transaction qui a passé les snakecoins a réussi (Statut: 200 OK). Cependant, cette transaction n'a pas encore été enregistrée dans la blockchain (= non terminée). Vous pouvez voir que le contenu n'a pas changé même si vous cliquez sur GET / blocks
.
Faisons du minage pour terminer la transaction de livraison. Appuyez sur «POST / mines».
Les informations de bloc nouvellement créées sont renvoyées. En plus des informations de livraison de 2 snakecoins, les informations de livraison de 1 snakecoin sont incluses en récompense du mineur (mineur).
Si vous cochez GET / blocks
, vous pouvez voir que de nouveaux blocs ont été ajoutés à la blockchain.
La blockchain ne fait pas peur!
Je veux toujours en savoir plus sur le PoS (Proof of Stake) d'Etherium, pas sur le PoW, comme la construction d'un réseau P2P ou la mise en œuvre de Wallet! Je sens qu'il y a diverses pénuries, mais je sens que j'ai atteint le point où je comprends parfaitement la blockchain ().
Il y a encore des choses qui doivent être étudiées avant de l'utiliser, mais du point où «je ne vois pas le chemin du fonctionnement réel» à «je pense que je peux faire un système de points pour m'amuser un peu plus». pense. Mais après tout, la mise en œuvre autour de l'exploitation minière donne-t-elle également au client une fonction de serveur? Je n'en suis toujours pas sûr, alors j'ai pensé étudier en lisant Article du calendrier de l'Avent.
J'espère que cela vous aidera à comprendre la blockchain. Et merci encore à M. Gerald.
demain? Est-ce que @ shu-kob Let's touch Bitcoin Signet.
Recommended Posts