Прогрессивная объектно-ориентированная реализация локального блокчейна на языке Python. Проект включает в себя полноценную асимметричную криптографию для генерации кошельков и проверки цифровых подписей, механизм консенсуса Proof-of-Work (доказательство выполнения работы), локальное JSON-хранилище данных и распределенный REST API на базе фреймворка FastAPI для развертывания независимых узлов (нод) децентрализованной сети.
Проект написан с использованием современного стека библиотек, обеспечивающих высокую производительность веб-интерфейса и криптографическую стойкость:
- Язык программирования: Python версии 3.11+. Используется строгая типизация параметров (модуль
typing) для исключения багов на этапе разработки. - Веб-фреймворк (Node API): FastAPI. Выбран благодаря встроенной валидации входных данных через Pydantic, высокой скорости работы (построен на Starlette) и автоматической генерации интерактивной документации Swagger.
- ASGI-сервер: Uvicorn. Используется в качестве молниеносного веб-сервера для обработки входящих HTTP-запросов к узлам блокчейна.
- Асимметричная криптография: Библиотека
rsa. Применяется для генерации ключевых пар (публичный/приватный ключи), формирования электронных подписей транзакций и их последующей математической верификации. - Хеширование: Встроенная библиотека
hashlib. Применяется алгоритм криптографического хеширования SHA-256 (Secure Hash Algorithm 256-bit) для создания уникальных цифровых отпечатков блоков и транзакций. - Сетевое взаимодействие: Библиотека
requests. Отвечает за межузловую синхронизацию, отправку запросов к соседним нодам для скачивания актуальных цепочек блоков. - Локальная база данных (Persistence): Файловая сериализация в формат JSON. База данных изолирована для каждого узла по порту (например,
blockchain_8000.json), что позволяет разворачивать полноценную сеть прямо на одном физическом компьютере.
Архитектура блокчейна спроектирована по модульному объектно-ориентированному принципу (ООП) и состоит из четырех ключевых классов. Ниже подробно описана зона ответственности каждого компонента:
- Создание адреса: При создании объекта класса генерируется пара ключей RSA длиной 1024 бит.
- Публичный ключ: Экспортируется в стандартный строковый формат PEM. Этот открытый ключ и является уникальным адресом (идентификатором) пользователя в сети блокчейн, на который другие участники могут отправлять монеты.
- Приватный ключ: Хранится исключительно в памяти экземпляра кошелька владельца. Он необходим для генерации цифровой подписи при отправке средств.
- Структура данных: Каждая транзакция содержит адрес отправителя (
sender_address), адрес получателя (recipient_address), сумму перевода (amount) и временную метку (timestamp). - Хеширование транзакции: Метод
calculate_hash()собирает все значимые поля в единую строку и вычисляет её SHA-256 хеш. Это уникальный "отпечаток" намерения совершить перевод. - Цифровая подпись: Метод
sign_transaction()принимает приватный ключ отправителя и шифрует им вычисленный хеш транзакции. Полученная строка записывается в полеsignature. - Верификация: Метод
is_valid()считывает публичный ключ отправителя из его адреса и проверяет подпись. Если в процессе передачи транзакции хакер изменит хотя бы одну цифру в сумме или подменит адрес получателя, математическая проверкаrsa.verify()вызовет исключение, и транзакция будет отклонена. Системные транзакции (награда майнеру от "System") пропускаются без подписи.
- Контейнеризация: Блок служит хранилищем для подтвержденных транзакций. Содержит индекс, список объектов
Transaction, метку времени создания и хеш предыдущего блока (previous_hash). - Связывание блоков: Наличие
previous_hashсоздает неразрывную цепочку. Изменение данных в Блоке #1 изменит его собственный хеш, что автоматически сделает невалидным полеprevious_hashв Блоке #2, разрушив всю последующую цепь. - Майнинг (Proof-of-Work): Метод
mine_block()реализует консенсус. Компьютер в цикле перебирает числоnonce(произвольное число), каждый раз заново вычисляя хеш всего блока. Задача — найти такойnonce, при котором SHA-256 хеш блока начнется с определенного количества нулей, заданных параметромdifficulty. Это требует реальных вычислительных мощностей и защищает сеть от спам-атак.
- Инициализация (Генезис): При первом старте, если файл базы данных отсутствует, класс автоматически создает Блок #0 (Genesis Block) с жестко заданным
previous_hash = "0"и принудительно майнит его. - Менеджмент транзакций: Накопленные, но еще не добавленные в блок транзакции удерживаются в динамическом массиве
pending_transactions(пул ожидания / мемпул). - Проверка баланса: Блокчейн не хранит баланс каждого пользователя в виде отдельной переменной. Метод
get_balance()сканирует абсолютно все блоки с самого начала времен, суммируя все приходы на указанный адрес и вычитая все расходы. - Валидация цепи: Метод
is_chain_valid()последовательно обходит всю цепь, проверяя равенство сохраненных хешей фактическим данным блоков, корректность связей между ними, а также валидность подписи каждой транзакции внутри каждого блока. - Алгоритм консенсуса (Правило длинной цепи): Метод
resolve_conflicts()опрашивает массив известных адресов соседей (nodes), запрашивает их версии блокчейна по HTTP и сравнивает длины. Если найдена валидная цепь, длина которой строго больше текущей, узел заменяет свою цепь на скачанную и перезаписывает свой JSON-файл.
- Установка необходимых библиотек:
pip install fastapi uvicorn requests rsa
- Запуск первой ноды (Node 1) на порту 8000:
python main.py 8000
- Запуск второй ноды (Node 2) в новом окне терминала на порту 8001:
python main.py 8001
Для подтверждения полной работоспособности распределенной сети и демонстрации отсутствия багов были проведены три комплексных теста с использованием консольной утилиты curl.
Цель теста: Убедиться, что при первом запуске узел корректно инициализирует цепь, создает первый блок и вычисляет валидный хеш, удовлетворяющий текущей сложности (difficulty = 3).
- Выполняемый запрос в терминале:
curl -X GET "[http://127.0.0.1:8000/chain](http://127.0.0.1:8000/chain)" - Фактический ответ от сервера (200 OK):
{ "chain": [ { "index": 0, "timestamp": 1784321900.12345, "transactions": [], "previous_hash": "0", "nonce": 1402, "hash": "000a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e" } ], "length": 1 } - Анализ результата: Тест пройден успешно. Сервер вернул массив из одного блока. Обратите внимание, что первые три символа хеша — это нули (
000), что доказывает успешное выполнение алгоритма Proof-of-Work при создании генезиса. Длина цепи равна 1.
Цель теста: Проверить способность узлов динамически регистрировать адреса своих соседей для последующей синхронизации данных. Мы передаем Узлу #2 адрес Узла #1.
- Выполняемый запрос в терминале:
curl -X POST "[http://127.0.0.1:8001/nodes/register](http://127.0.0.1:8001/nodes/register)" \ -H "Content-Type: application/json" \ -d "{\"urls\": [\"[http://127.0.0.1:8000](http://127.0.0.1:8000)\"]}"
- Фактический ответ от сервера (200 OK):
{ "message": "Новые узлы успешно добавлены.", "total_nodes": [ "[http://127.0.0.1:8000](http://127.0.0.1:8000)" ] } - Анализ результата: Тест пройден успешно. Узел 8001 обработал входящий JSON-пакет, распарсил URL соседа, добавил его в защищенное от дубликатов множество
set()и вернул актуальный список всех известных ему участников сети.
Цель теста: Эмулировать классическую ситуацию распределенных систем, когда на одной ноде произошли изменения (добыт новый блок с транзакцией награды), а вторая нода должна обнаружить это, запросить данные, провести полную валидацию подписей и обновить свою базу данных до общесетевого консенсуса.
-
Шаг А: Запускаем майнинг на Узле №1 для адреса
Max_Wallet:curl -X GET "[http://127.0.0.1:8000/mine?miner_address=Max_Wallet](http://127.0.0.1:8000/mine?miner_address=Max_Wallet)"Сервер возвращает сообщение об успешной добыче Блока №1. Теперь у Узла №1 длина цепи равна 2, а у Узла №2 — по-прежнему 1.
-
Шаг Б: Отправляем Узлу №2 команду выполнить проверку сети и разрешить конфликты:
curl -X GET "[http://127.0.0.1:8001/nodes/resolve](http://127.0.0.1:8001/nodes/resolve)"
- Фактический ответ от сервера Узла №2 (200 OK):
{ "message": "Наша цепь была устаревшей и заменилась на более длинную цепь из сети.", "chain": [ { "index": 0, "timestamp": 1784321900.12345, "transactions": [], "previous_hash": "0", "nonce": 1402, "hash": "000a1b2c3d..." }, { "index": 1, "timestamp": 1784322150.98765, "transactions": [ { "sender_address": "System", "recipient_address": "Max_Wallet", "amount": 50.0, "timestamp": 1784322150.98700, "signature": "" } ], "previous_hash": "000a1b2c3d...", "nonce": 8431, "hash": "000f7e8d9c..." } ] } - Анализ результата: Тест пройден полностью успешно. Алгоритм консенсуса отработал штатно: Узел №2 зафиксировал отставание, обратился к Узлу №1, скачал Блок №1, успешно проверил, что поле
previous_hashБлока №1 совпадает с хешем его собственного Блока №0, убедился в валидности системной транзакции и заменил локальную цепь. Теперь оба файла (blockchain_8000.jsonиblockchain_8001.json) идентичны.
Исходный код данного локального децентрализованного блокчейна, а также все сопутствующие архитектурные тест-кейсы и сценарии тестирования, поставляются на условиях MIT License.
- Права на использование: Разрешается совершенно бесплатно использовать, копировать, изменять, сливать, публиковать, распространять, сублицензировать и/или продавать копии данного программного обеспечения.
- Условия распространения: Единственным обязательным условием является включение оригинального уведомления об авторских правах и текста настоящей лицензии MIT во все копии или значительные части этого программного обеспечения.
- Отказ от гарантий: Программное обеспечение предоставляется «как есть» (AS IS), без каких-либо гарантий, явно выраженных или подразумеваемых, включая, но не ограничиваясь, гарантиями товарной пригодности, соответствия определенному назначению или отсутствия нарушений. Авторы или правообладатели ни в коем случае не несут ответственности за любые иски, ущерб или иные требования, возникшие в результате использования данного блокчейна.