Разработать два микросервиса, взаимодействующие друг с другом для реализации API сервиса голосования. Общение между ними должно работать через GRPC.
Должен иметь следующие grpc методы:
- GetBalance - получение баланса по ethereum адресу.
- GetLatestBlock - получение информации по последнему блоку. Метод должен вернуть номер блока, количество транзакций, сложность блока и время создания.
- VerifyAddress - проверка адреса на валидность и то что он не является смарт контрактом.
Необходимые сущности:
- Proposal - предложение за которое могут голосовать пользователи. Должно содержать следующие данные: заголовок предложения, описание предложения.
- Vote - голос пользователя, можно голосовать только за или против какого-либо Proposal. Должен содержать следующие данные: голос (за или против), баланс пользователя на момент голоса, номер текущего блока на момент голоса.
- User - пользователь, который может голосовать. Должен содержать следующие данные: адрес пользователя в сети Эфир, номер блока на момент регистрации пользователя.
- Admin - пользователь с правами на редактирование Proposal. В остальном аналогичен обычному пользователю.
Необходимые методы:
- Create Proposal - создание Proposal (доступно только Admin).
- Update Proposal - редактирование данных Proposal (доступно только Admin), недоступно если за Proposal уже голосовали.
- Delete Proposal - удаление Proposal (доступно только Admin), недоступно если за Proposal уже голосовали.
- Get Proposals - получение всех Proposal.
- Register User - регистрация нового пользователя. На вход подается адрес, метод должен проверять адрес на валидность с помощью метода VerifyAddress 1-го сервиса, а также записывать текущий блок в сети на момент регистрации (использовать метод GetLatestBlock 1-го сервиса).
- Create Vote - запись голоса пользователя за какое-либо предложение. Голос пользователя учитывается, только если его баланс на момент голосования больше 0 (использовать метод GetBalance 1-го сервиса), в противном случае необходимо выдать ошибку. Баланс пользователя и номер текущего блока в сети необходимо записать вместе с голосом.
- Get Votes - получение суммарной информации о голосовании за конкретное предложение (сумма балансов голосов за и сумма балансов голосов против).
Сервис должен реализовать все методы необходимые для системы голосования, для реализации некоторых методов использовать обращения при помощи gRPC к внешнему микросервису (1-ый сервис) для получения данных из блокчейн сети.
Реализовано 2 микросервиса и спроектирована база данных для первого микросервиса, которые общаются между собой через gRPC:
1. Сервис голосования (microservice1)
- Реализован в виде REST API.
- В конце приведено описание для пары основных методов
- Остальные можно найти в Swagger документации после развертывания приложения по адресу host:port/docs. Там вы можете подробно ознакомиться со всеми методами и даже их пощупать. 2. Сервис для работы с ethereum (microservice2)
- Служит для получения, обработки и передачи информации об ethereum.
- Имеет следующие gRPC методы:
- GetBalance получает адрес кошелька (address) и отдает его баланс (balance);
- GetLatestBlock ничего не получает, отдает номер последнего блока (number) на момент выполнения, количество транзакций (count_transactions), сложность блока (difficulty) и время создания (time);
- VerifyAddress получает адрес кошелька (address), проверяет его подлинность и отдает булевый ответ (is_verified); 3. База данных
- Реализовано 3 сущности - Proposal, User, Vote.
- Между сущностями Proposal и User существует связь Многие-ко-Многим через ассоциативную таблицу Vote.
- Сервис 1 разработан с использованием ЯП Python, фреймворков FastAPI для реализации API, SQLAlchemy для работы с базой данных, библиотека uvicorn для запуска сервера и др.
- В качестве БД использовался PostgreSQL. Для обеспечения корректной связи FastAPI и PostgreSQL использовалась библиотека asyncopg.
- Сервис 2 разработан с использованием ЯП Python, фреймворка web3 для работы с ethereum, библиотеки grpcio для реализации общения через gRPC и др.
- Микросервисы и база данных обернуты в Docker-контейнеры и запускаются при помощи docker compose
Приложение развертывается и запускается через docker.
Для запуска приложения необходимо:
Скачать из проекта docker-compose.yml или сделать свой с данными из репозитория:
В нем заполнить следующие переменные окружения:
- SECRET_KEY_TOKEN - для хешириваноя паролей пользователей. Его можно сгенерировать с помощью команды:
openssl rand -hex 32
- INFURA_ENDPOINT - публичная нода для работы с ethereum
Выполнить команду запуска контейнеров
docker compose up
- Перейти по адресу 0.0.0.0:8000/docs. Это Swagger документация.
- Необходимо создать пользователя и авторизоваться. Находим метод api_v1_auth_register и заполняем данные.
- Далее ищем серый открый замок у любого из методов, нажимаем и вводим username и password.
- Сервис готов. Балуйтесь :)
На удаленной машине алгоритм аналогичен. Изменится только адрес. Необходимо перейти на адрес удаленной машины. Порт 8000. Наример, я развернул проект на своем удаленном виртуальном сервере. Он доступен по адресу http://45.131.40.80:8000/docs.
Name | Description |
---|---|
ENDPOINT: | /api/v1/auth/register |
METHOD: | POST |
PARAMETERS: | None |
INPUT VALUES: | { |
"username": "string", | |
"hashed_password": "string", | |
"email": "string", | |
"wallet_address": "string", | |
"is_superuser": false | |
} | |
OUTPUT VALUES: | { |
"username": "string", | |
"email": "string", | |
"wallet_address": "string", | |
"block_number": 0, | |
"is_superuser": false, | |
"is_active": true | |
} | |
ENDPOINT: | /api/v1/proposals |
METHOD: | POST |
PARAMETERS: | None |
INPUT VALUES: | { |
"title": "string", | |
"description": "string", | |
} | |
OUTPUT VALUES: | { |
"title": "string", | |
"description": "string", | |
} | |
ENDPOINT: | /api/v1/votes/{proposal_id} |
METHOD: | POST |
PARAMETERS: | "proposal_id": "int" |
INPUT VALUES: | { |
"is_like": "bool" | |
} | |
OUTPUT VALUES: | { |
"proposal_id": 0, | |
"user_id": 0, | |
"is_like": false, | |
"user_balance": "string", | |
} |
В коде есть парочка недоочетов, в дальнейшем необходимо провести локализацию текстов ошибок, привести ответы к единому стандартизированному виду и предусмотреть все возможные ошибки, связанные с действиями пользователей.