Строим собственный блокчейн на Python и разбираемся в его особенностях



Книга Строим собственный блокчейн на Python и разбираемся в его особенностях

Перед тем как начать строить блокчейн, необходимо понять его основы.


Блокчейн  —  это технология, используемая для записи и хранения данных. Например, он может содержать информацию о переводах, которые проводятся в любом банке, а также права собственности, соглашения, личные сообщения и другие данные.


Его главная особенность заключается в том, что хранение данных не происходит в одном центральном органе. Благодаря этому не получится сфальсифицировать данные, взломав только один главный пункт. Самое известное применение блокчейна  —  это 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!


517   0  

Comments

    Ничего не найдено.