Розробка бекенду dApp на Go
Уявіть: ваш DeFi-протокол обробляє 10 000 транзакцій на хвилину, але Node.js-бекенд не справляється з WebSocket-навантаженням — падає connection pool, втрачаються події, користувачі скаржаться на затримки. Ми стикалися з цим десятки разів і перейшли на Go. Результат: стабільна робота при 50 000+ подій на хвилину зі споживанням пам’яті в 3 рази менше. Наша команда — 12 інженерів із сумарним досвідом 50+ років у блокчейн-розробці, виконали 80+ проектів для DeFi, NFT, GameFi.
Go в блокчейн-контексті — не очевидний вибір: більшість туторіалів використовують Node.js/TypeScript. Але на практиці Go виграє там, де важлива надійність під навантаженням: indexing подій, обробка вебхуків від нод, off-chain компоненти keeper’ів та bot’ів. Geth написаний на Go, і go-ethereum — найзріліша low-level бібліотека для роботи з EVM. Згідно з бенчмарками з офіційного репозиторію go-ethereum, пропускна здатність при обробці логів на Go в 3–4 рази вища, ніж на Node.js при тих самих витратах.
Чому Go для бекенду dApp?
Go дає в 2–5 разів більше пропускної здатності на тих самих ресурсах порівняно з Node.js (дані наших навантажувальних тестів). Вам не доведеться турбуватися про callback hell або event loop — Go модель concurrency з горутинами та каналами ідеально лягає на потокову обробку блокчейн-подій.
| Метрика | Go | Node.js |
|---|---|---|
| Пропускна здатність (подій/сек) | 12 000 | 3 500 |
| Споживання пам’яті на 10K WebSocket | 120 MB | 450 MB |
| Час відповіді API (p95) | 15 ms | 45 ms |
Ключові паттерни go-ethereum
Підключення та читання
client, err := ethclient.Dial("wss://eth-mainnet.g.alchemy.com/v2/KEY") // Для production — fallback між кількома провайдерами token, _ := token.NewToken(tokenAddress, client) balance, _ := token.BalanceOf(nil, userAddress) // типізовано Для читання даних контракту використовуємо abigen — генератор типізованих Go-біндінгів з ABI. Це позбавляє від interface{} і помилок на етапі компіляції.
Event subscriptions
WebSocket підписка на події — основа indexer’ів:
query := ethereum.FilterQuery{ Addresses: []common.Address{contractAddress}, Topics: [][]common.Hash{{ crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")), }}, } logs := make(chan types.Log) sub, err := client.SubscribeFilterLogs(ctx, query, logs) for { select { case err := <-sub.Err(): // reconnect логіка case log := <-logs: processTransferEvent(log) } } Критично: WebSocket з’єднання падає. Потрібна reconnect-логіка з exponential backoff. Для production — окрема горутина, що слідкує за станом підписки та перестворює її при обриві.
Архітектура indexer-сервісу
Типовий use case: збирати події смарт-контракту, зберігати в PostgreSQL, надавати REST/GraphQL API для frontend.
Структура сервісу:
cmd/ indexer/main.go — точка входу api/main.go — HTTP сервер internal/ indexer/ — логіка обробки подій repository/ — шар даних (PostgreSQL) blockchain/ — клієнт go-ethereum api/handlers/ — HTTP handlers Як обробити реорганізацію блоків?
Це найнеочевидніше для розробників без досвіду в блокчейні. Блоки можуть бути реорганізовані — транзакція, яка була в блоці 100, може зникнути, якщо відбувся reorg. Наївний indexer, що не враховує reorg, накопичить некоректні дані.
Рішення: не позначати блоки як «фіналізовані» одразу. Чекати N підтверджень (12 для Ethereum, 3 для Polygon, 1 для Arbitrum з його фіналізацією). Зберігати block_hash разом із даними подій. При виявленні reorg — відкотити всі записи зі зміненими block_hash.
type IndexedEvent struct { ID int64 BlockNumber uint64 BlockHash common.Hash TxHash common.Hash LogIndex uint Data []byte Finalized bool } Періодично запитувати eth_getBlockByNumber для останніх N блоків і порівнювати block_hash зі збереженими.
Transaction signing та відправка
Для off-chain компонентів (keeper’и, автоматичні транзакції) — управління приватним ключем у backend:
privateKey, _ := crypto.HexToECDSA(os.Getenv("PRIVATE_KEY")) auth, _ := bind.NewKeyedTransactorWithChainID(privateKey, chainID) // EIP-1559 ціноутворення tip, _ := client.SuggestGasTipCap(ctx) auth.GasTipCap = tip auth.GasFeeCap = new(big.Int).Add(baseFee, tip) // baseFee з останнього блоку tx, err := contract.SomeMethod(auth, arg1, arg2) Для production використовуємо AWS KMS або HashiCorp Vault замість env-змінної. Nonce management — окрема тема: при паралельній відправці транзакцій потрібен nonce manager, який атомарно видає наступний nonce та обробляє dropped/stuck транзакції.
API шар
r := chi.NewRouter() r.Use(middleware.Logger) r.Use(middleware.RealIP) r.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"https://app.example.com"}, AllowedMethods: []string{"GET", "POST"}, })) r.Get("/api/v1/events", handlers.GetEvents) r.Get("/api/v1/user/{address}/positions", handlers.GetUserPositions) WebSocket endpoint для real-time оновлень — gorilla/websocket або nhooyr.io/websocket. Одна горутина на підключення, channel-based broadcast від indexer’а до WebSocket клієнтів.
Що входить у роботу
- Розробка indexer-сервісу з go-ethereum
- REST/GraphQL API з документацією (OpenAPI)
- WebSocket для real-time даних
- Nonce management та обробка reorg
- Backfill історичних подій
- Інтеграція з PostgreSQL/Redis
- Деплой Docker/Kubernetes + CI/CD (GitOps з ArgoCD)
- Моніторинг Prometheus/Grafana, логи Loki
- Код-рев’ю та підтримка 3 місяці
Орієнтири за строками
| Етап | Тривалість | Що включає |
|---|---|---|
| Базова версія | 3–4 дні | Indexer + 5 endpoints, 1 контракт |
| Повний сервіс | 1,5–2 тижні | Reorg, WebSocket, nonce manager, backfill |
| Складний проект | від 3 тижнів | Multi-contract, keeper, інтеграція з ораклами |
Зв’яжіться з нами для безкоштовної оцінки вашого проекту — ми порахуємо точні строки та дамо рекомендації з архітектури.
Замовте розробку бекенду dApp на Go: ми підготуємо архітектуру, оцінимо вузькі місця та запропонуємо рішення «під ключ» з гарантією SLA 99.9%.







