Надійний бекенд для dApp на Python: web3.py, FastAPI, Celery
Чому Python для бекенду dApp?
Уявіть: DeFi-агрегатор має кожні 5 хвилин оновлювати ціни з 20 пулів, розраховувати impermanent loss і надсилати транзакції з мінімальним slippage. Синхронний Flask тут не впорається — блокчейн дає блок раз на 12–15 секунд, а кожен HTTP-запит чекає відповіді від RPC. Python з асинхронним стеком вирішує це: web3.py для блокчейну, FastAPI для API, Celery для фонових завдань. Наша компанія має 7+ років досвіду і реалізувала 10+ таких проєктів: від NFT-маркетплейсів до DeFi-агрегаторів з APY-калькуляторами. Асинхронний стек забезпечує пропускну здатність у 10 разів вищу за синхронний (див. таблицю нижче).
web3.py provide a smooth interface to interact with Ethereum nodes — документація web3.py
Як web3.py спрощує взаємодію з блокчейном?
web3.py — зріла бібліотека для роботи з EVM-мережами. Основні складнощі: перевірка checksum-адрес і PoA-мідлварі. Без Web3.to_checksum_address() будь-яке звернення до зовнішнього джерела викличе помилку. Для Polygon і BNB Chain обов'язково підключаємо geth_poa_middleware. Приклад налаштування:
from web3 import Web3 from web3.middleware import geth_poa_middleware w3 = Web3(Web3.HTTPProvider("https://eth-mainnet.g.alchemy.com/v2/KEY")) w3.middleware_onion.inject(geth_poa_middleware, layer=0) balance = w3.eth.get_balance("0xChecksumAddress") contract = w3.eth.contract(address=checksum_address, abi=ABI) result = contract.functions.balanceOf(address).call() Як асинхронність і Celery вирішують проблему продуктивності?
Синхронний виклик блокчейну блокує event loop. Ми використовуємо FastAPI + async web3, а фонові завдання виносимо в Celery. Пропускна здатність зростає з ~50 до 500+ запитів/с — це в 10 разів краще. Використання Redis для кешування пришвидшує відповіді API у 5 разів порівняно з прямими викликами блокчейну. Celery-завдання обробляють тривалі операції: надсилання транзакцій, індексацію подій, синхронізацію цін. Приклад завдання з retry:
from celery import Celery from celery.schedules import crontab celery_app = Celery("dapp", broker="redis://localhost:6379/0") @celery_app.task(bind=True, max_retries=3) def send_transaction(self, contract_address, function_name, args): try: contract = w3.eth.contract(address=contract_address, abi=ABI) tx_hash = contract.functions[function_name](*args).transact({ "from": hot_wallet.address, "gas": 200000 }) return {"tx_hash": tx_hash.hex(), "status": "pending"} except Exception as exc: raise self.retry(exc=exc, countdown=30) celery_app.conf.beat_schedule = { "sync-prices": { "task": "tasks.sync_token_prices", "schedule": crontab(minute="*/5") } } Основні проблеми та часті помилки бекенду dApp
Nonce management. При паралельному надсиланні транзакцій два воркери можуть прочитати однаковий nonce — одна транзакція застрягне. Рішення: Redis-блокування з TTL або nonce pool. Економія до 30% на gas fees завдяки кешуванню даних — кожен зайвий виклик eth_call або eth_sendTransaction коштує грошей. Індексація подій. WebSocket-підписки ненадійні в production — використовуємо Alchemy Notify + Celery-завдання для пересинхронізації при збоях.
Докладніше про nonce management
Nonce — лічильник транзакцій від одного адреса. Без блокування два воркери можуть передати однаковий nonce. Ми використовуємо Redis-блокування: перед надсиланням воркер захоплює блокування на адресу, надсилає транзакцію, звільняє. TTL гарантує, що при краху блокування не залишиться назавжди.Часті помилки:
- Забути про nonce management. Без синхронізації при паралельних запитах транзакції застрягають.
- Використовувати Decimal для wei. Краще зберігати як рядок, щоб уникнути втрати точності.
- Не додати middleware для PoA-мереж. Інакше
get_blockвикине помилку. - Синхронні запити в API. Блокують event loop, знижують пропускну здатність у 10 разів.
Наш стек і приклади коду
| Характеристика | Синхронний (Flask + requests) | Асинхронний (FastAPI + async web3) |
|---|---|---|
| Пропускна здатність | ~50 запитів/с | 500+ запитів/с (в 10 разів більше) |
| Event loop блокування | Так | Ні |
| Celery | Потрібен | Потрібен, але менш критично |
| Складність налагодження | Низька | Середня |
| Сценарії | Прості проксі, мале навантаження | Високонавантажені DeFi, real-time |
FastAPI з Pydantic v2 для валідації:
from fastapi import FastAPI, HTTPException from pydantic import BaseModel, validator import re class TransactionRequest(BaseModel): address: str amount: str @validator("address") def validate_eth_address(cls, v): if not re.match(r"^0x[a-fA-F0-9]{40}$", v): raise ValueError("Invalid Ethereum address") return Web3.to_checksum_address(v) app = FastAPI() @app.get("/api/balance/{address}") async def get_balance(address: str): try: checksum = Web3.to_checksum_address(address) except ValueError: raise HTTPException(status_code=400, detail="Invalid address") balance_wei = w3.eth.get_balance(checksum) return { "address": checksum, "balance_eth": Web3.from_wei(balance_wei, "ether"), "balance_wei": str(balance_wei) } SQLAlchemy + PostgreSQL і зберігання wei як рядок:
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import DeclarativeBase, mapped_column, Mapped from datetime import datetime class Base(DeclarativeBase): pass class Transaction(Base): __tablename__ = "transactions" id: Mapped[int] = mapped_column(primary_key=True) tx_hash: Mapped[str] = mapped_column(unique=True, index=True) from_address: Mapped[str] = mapped_column(index=True) to_address: Mapped[str] = mapped_column(index=True) value_wei: Mapped[str] # рядок, не втрачає точність block_number: Mapped[int] = mapped_column(index=True) timestamp: Mapped[datetime] status: Mapped[str] Процес роботи та строки розробки
- Аналіз. Вивчаємо смарт-контракти, вимоги до API, бізнес-логіку. Складаємо ТЗ.
- Проєктування. Визначаємо архітектуру: структура БД, API-методи, Celery-завдання, схему підписання.
- Реалізація. Пишемо код, покриваємо тестами (pytest), інтегруємо з блокчейном.
- Тестування. Запускаємо на тестовій мережі, перевіряємо сценарії: надсилання транзакцій, обробка подій, відновлення після збоїв.
- Деплой. Розгортаємо в production з Docker, налаштовуємо моніторинг (grafana, loki).
| Етап | Тривалість | Вартість (орієнтовно) |
|---|---|---|
| Базова архітектура, web3.py-клієнти, REST API (read-only), PostgreSQL | 1 тиждень | від $1500 |
| Celery-завдання, indexer, SIWE-аутентифікація, підписання транзакцій | 1 тиждень | від $1500 |
| Складна бізнес-логіка (аналітика, ML) | від 3 днів | від $1000 |
Повний бекенд — від 1,5 до 2 тижнів, вартість від $3000. Замовляючи під ключ, ви отримуєте знижку 10%. Оцінимо ваш проєкт безкоштовно — пишіть!
Що ви отримуєте
- Архітектуру, адаптовану під вашу бізнес-логіку.
- REST API з OpenAPI-документацією.
- Індексатор подій з записом у PostgreSQL.
- Фонові завдання: надсилання транзакцій, синхронізація цін, health-чеки.
- Безпечне підписання з hot wallet або інтеграція з Vault/AWS KMS.
- Docker-контейнеризацію та документацію з розгортання.
- Гарантію на код 3 місяці та підтримку після здачі.
- Навчання вашої команди (до 4 годин).
- Доступи до репозиторію та CI/CD.
Зв'яжіться з нами для консультації — ми допоможемо обрати архітектуру та оцінимо строки. Замовте розробку бекенду вашого dApp вже сьогодні. Пишіть на пошту або в Telegram – відповімо за 2 години.







