Перед тем как начать строить блокчейн, необходимо понять его основы.
Блокчейн — это технология, используемая для записи и хранения данных. Например, он может содержать информацию о переводах, которые проводятся в любом банке, а также права собственности, соглашения, личные сообщения и другие данные.
Его главная особенность заключается в том, что хранение данных не происходит в одном центральном органе. Благодаря этому не получится сфальсифицировать данные, взломав только один главный пункт. Самое известное применение блокчейна — это Bitcoin, один из видов криптовалют.
Углубленное изучение блокчейна может вызвать трудности, а практика лучше всего помогает упростить этот процесс. Это руководство рассчитано на новичков с небольшими знаниями Python.
Требования
Убедитесь, что у вас установлена самая последняя версия Python, а также две его библиотеки — Flask и Requests.
pip install Flask request
Для создания запросов рекомендуем скачать Postman.
Начало
Создадим новый файл в Python и назовём его app.py
. Сначала нам нужно написать класс Blockchain
:
class Blockchain(object):
После создания конструктора добавляем пустой список для хранения блокчейна:
def __init__(self):
self.chain = []
Ещё нам понадобится список для хранения транзакций, поэтому получаем вот такой класс Blockchain
:
class Blockchain(object):
def __init__(self):
self.chain = []
self.current_transactions = []
Для внесения данных в эти списки создадим два метода: addBlock()
и addTransaction()
.
def addBlock(self):
pass
def addTransaction(self):
pass
Пока эти функции не будут выполнять никаких действий, но скоро мы к ним вернёмся.
Далее хешируем данные, чтобы обезопасить их. Создадим метод hash()
. Поскольку он статический, не забудьте добавить @staticmethod
:
@staticmethod
def hash(block):
pass
И наконец напишем метод lastBlock()
:
@property
def lastBlock(self):
pass
Создание блока
Теперь подумаем над тем, как будет выглядеть блок. В первую очередь для него нужен индекс index
и временной штамп timestamp
. А как же Proof? Что это? К этому мы вернёмся позже.
Также необходимо добавить список транзакций transactions
и хеш предыдущего блока previous_hash
.
Внесение новых транзакций
Новые транзакции создаём с помощью метода addTransaction()
. Теперь заполним его кодом.
Сначала введём несколько аргументов: self
, sender
, recipient
, amount
.
def new_transaction(self, sender, recipient, amount):
Далее добавим новую транзакцию в список:
self.current_transactions.append({
‘sender’: sender,
‘recipient’: recipient,
‘amount’: amount,
})
В конце этот метод должен возвращать индекс транзакции:
return self.last_block[‘index’] + 1
Что придаёт ему такой вид:
def addTransaction(self, sender, recipient, amount):
self.current_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount,
})
return self.last_block['index'] + 1
Создание нового блока
Прежде чем начать строить новые блоки, нужно создать в конструкторе один центральный блок:
self.new_block(previous_hash=1, proof=100)
Затем заполняем метод addBlock()
:
def addBlock(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.chain[-1]),
}
self.current_transactions = []
self.chain.append(block)
return block
Как вы могли заметить, нужно создать метод hash()
, чтобы код заработал.
@staticmethod
def hash(block):
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
Использовать хеширование довольно легко. По сути, это шифрование строки.
Дальше нам нужно добавить ещё один метод — lastBlock()
:
@property
def last_block(self):
return self.chain[-1]
Что такое Proof
Proof of Work (доказательство выполнения работы) — это алгоритм, основная цель которого препятствовать кибератакам, например DDoS-атаке. Впервые идея о Proof of Work (PoW) была опубликована Синтией Дворк и Мони Наором в 1993 году.
Такой алгоритм необходим для интенсивных вычислений (также называемых «майнинг»), благодаря которым ненадёжные транзакции отсекаются в отдельную группу в блокчейне.
Чтобы подтвердить надёжность таких транзакций, майнеры должны решить математическую задачу. И тот, кто решит первым, получает вознаграждение (в виде новой криптовалюты). С каждым новым блоком задачи становятся чуть сложнее. Поэтому майнерам приходится работать эффективнее. Подтверждённые же транзакции хранятся в публичном блокчейне.
Применение PoW
Теперь реализуем Proof of Work для нашего блокчейна со следующей задачей:
Найти число х. Когда оно хешируется предыдущим решением блока, создаётся хеш с 2 заглавными нулями.
Чтобы её внести, добавим следующие модули:
import hashlib
import json
from time import time
from uuid import uuid4
Напишем два новых методов:
def proof_of_work(self, last_proof):
И:
@staticmethod
def valid_proof(last_proof, proof):
Заполним их вот так:
def proof_of_work(self, last_proof):
proof = 0
while self.valid_proof(last_proof, proof) is False:
proof += 1
return proof
@staticmethod
def valid_proof(last_proof, proof):
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000"
Применение Flask для API
Конечно, строить блокчейн интересно, но теперь пришло время его использовать. И у Python есть прекрасный модуль Flask, чтобы создать API. Добавим немного базового кода Flask:
from flask import Flask
app = Flask(__name__)
node_identifier = str(uuid4()).replace('-', '')
blockchain = Blockchain()
@app.route('/mine', methods=['GET'])
def mine():
return "Mining a new Block"
@app.route('/transactions/new', methods=['POST'])
def new_transaction():
return "Adding a new Transaction"
@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)
Подробнее о Flask можно узнать из его документации.
Новые транзакции
Конечная точка новых транзакций для API будет выглядеть таким образом. Довольно легко, ведь мы уже писали подобный метод:
@app.route('/transactions/new', methods=['POST'])
def newTransaction():
values = request.get_json()
required = ['sender', 'recipient', 'amount']
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'Transaction 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,
)
previous_hash = blockchain.hash(last_block)
block = blockchain.new_block(proof, previous_hash)
response = {
'message': "New Block Created",
'index': block['index'],
'transactions': block['transactions'],
'proof': block['proof'],
'previous_hash': block['previous_hash'],
}
return jsonify(response), 200
Запуск API блокчейна
Запустим API, открыв программу Python:
$ python app.py
$ Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Для майнинга блока можно использовать Postman или Curl:
$ curl -X POST -H "Content-Type: application/json" -d '{
"sender": "d4ee26eee15148ee92c6cd394edd974e",
"recipient": "address2",
"amount": 5
}' "http://localhost:5000/transactions/new"
А узнать количество замайненных блоков можно на http://localhost:5000/chain. Появится цепь в формате JSON:
{
"chain": [
{
"index": 1,
"previous_hash": 1,
"proof": 100,
"timestamp": 1606910340,
"transactions": []
},
}
Полный код
mport requests
from time import time
import hashlib
import json
from flask import Flask
from time import time
from uuid import uuid4
class Blockchain(object):
app = Flask(__name__)
node_identifier = str(uuid4()).replace('-', '')
blockchain = Blockchain()
@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,
)
previous_hash = blockchain.hash(last_block)
block = blockchain.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 newTransaction():
values = request.get_json()
required = ['sender', 'recipient', 'amount']
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'Transaction will be added to Block {index}'}
return jsonify(response), 201
@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)
def __init__(self):
self.chain = []
self.current_transactions = []
def proof_of_work(self, last_proof):
proof = 0
while self.valid_proof(last_proof, proof) is False:
proof += 1
return proof
@staticmethod
def valid_proof(last_proof, proof):
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000"
def addBlock(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.chain[-1]),
}
self.current_transactions = []
self.chain.append(block)
return block
def addTransaction(self, sender, recipient, amount):
self.current_transactions.append({
'sender': sender,
'recipient': 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]
Заключение
На этом всё. Вот как вы можете создать простой блокчейн на Python!
Читайте также:
- Надоело работать во фронтенд с JavaScript? Используйте Python для браузера!
- Суть 4 хитроумных концепций Python для новичков
- 10 идиоматических приемов для эффективного программирования на Python
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Bryan Dijkhuizen: Understand Blockchains by Building Your Own in Python