Разработка блокчейн-инфраструктуры
"Инфраструктура" — это всё, что находится между блокчейном и вашим продуктом. Смарт-контракты написаны, но без нод, индексеров, event processing pipeline и мониторинга они бесполезны в production. Именно инфраструктурные ошибки убивают проекты, которые уже прошли аудит смарт-контрактов: потерянные события, downtime RPC провайдера в момент высокой нагрузки, отсутствие replay механизма при падении сервиса.
Слои блокчейн-инфраструктуры
┌─────────────────────────────────────────────────────┐
│ Application Layer │
│ (Frontend, API, Business Logic) │
├─────────────────────────────────────────────────────┤
│ Data Access Layer │
│ (GraphQL API, REST API, WebSocket) │
├─────────────────────────────────────────────────────┤
│ Indexing Layer │
│ (The Graph / custom indexer / event processor) │
├─────────────────────────────────────────────────────┤
│ Node Layer │
│ (Archive node / full node / light client) │
├─────────────────────────────────────────────────────┤
│ Blockchain Layer │
│ (Ethereum / L2 / custom chain) │
└─────────────────────────────────────────────────────┘
Каждый слой имеет свои требования к надёжности и масштабированию. Разберём каждый.
Node Layer: своя нода или RPC провайдер
Когда нужна своя нода
RPC провайдеры (Infura, Alchemy, QuickNode) — правильный выбор для 80% проектов. Они решают операционные задачи, дают SLA, масштабируются автоматически.
Своя нода нужна когда:
-
Требуется archive node для исторических запросов (
eth_callпо прошлым блокам) — провайдеры берут за это отдельно и дорого - Rate limits критичны — при 100k+ запросов в день провайдер либо дорог, либо ограничивает
- Приватность — провайдер видит все запросы; для протоколов где метаданные транзакций чувствительны
- Специфические методы — некоторые debug/trace методы недоступны у провайдеров
Запуск Geth/Reth
# Reth (Rust Ethereum) — быстрее синхронизируется чем Geth
reth node \
--chain mainnet \
--http \
--http.addr 0.0.0.0 \
--http.port 8545 \
--http.api eth,net,web3,debug,trace \
--ws \
--ws.addr 0.0.0.0 \
--ws.port 8546 \
--authrpc.addr 127.0.0.1 \
--authrpc.port 8551 \
--authrpc.jwtsecret /path/to/jwt.hex \
--datadir /data/reth
Reth требует consensus client (Lighthouse, Prysm) для post-merge Ethereum. Это две ноды, которые общаются через Engine API.
Требования к железу (Ethereum full node):
- CPU: 4+ cores
- RAM: 16+ GB (32 GB рекомендуется)
- SSD: 2+ TB NVMe (не HDD, не SATA SSD — только NVMe для archive)
- Bandwidth: 25+ Mbps стабильно
Время синхронизации Reth от genesis: ~24–48 часов для full node, ~2–4 дня для archive.
Мультиплексирование RPC
Даже с одним провайдером нужен failover. Паттерн — load balancer с health checks:
class RpcMultiplexer {
private providers: JsonRpcProvider[];
private healthStatus: Map<string, boolean> = new Map();
constructor(endpoints: string[]) {
this.providers = endpoints.map(url => new JsonRpcProvider(url));
this.startHealthChecks();
}
async getHealthyProvider(): Promise<JsonRpcProvider> {
const healthy = this.providers.filter(
(p, i) => this.healthStatus.get(String(i)) !== false
);
if (healthy.length === 0) throw new Error('No healthy RPC providers');
// Round-robin среди здоровых
return healthy[Math.floor(Math.random() * healthy.length)];
}
private startHealthChecks(): void {
setInterval(async () => {
for (let i = 0; i < this.providers.length; i++) {
try {
await this.providers[i].getBlockNumber();
this.healthStatus.set(String(i), true);
} catch {
this.healthStatus.set(String(i), false);
}
}
}, 15_000);
}
}
Indexing Layer: The Graph vs кастомный индексер
The Graph
Для большинства EVM проектов The Graph — правильный выбор. Пишете subgraph (AssemblyScript + GraphQL schema), деплоите в Subgraph Studio, получаете GraphQL API.
# subgraph.yaml
specVersion: 0.0.5
schema:
file: ./schema.graphql
dataSources:
- kind: ethereum
name: MyProtocol
network: mainnet
source:
address: "0x..."
abi: MyProtocol
startBlock: 19000000
mapping:
kind: ethereum/events
apiVersion: 0.0.7
language: wasm/assemblyscript
entities:
- Deposit
- Withdrawal
abis:
- name: MyProtocol
file: ./abis/MyProtocol.json
eventHandlers:
- event: Deposited(indexed address,uint256)
handler: handleDeposit
file: ./src/mappings.ts
Плюс: decentralized (можно использовать через The Graph Network — платите GRT токенами), быстрый старт, GraphQL из коробки.
Минус: ограниченные возможности в обработчиках (нет произвольных HTTP вызовов, нет сложной бизнес-логики), AssemblyScript вместо TypeScript, debugging неудобен.
Кастомный индексер
Нужен когда: требуется сложная обработка событий, несколько контрактов с зависимыми данными, cross-chain данные, или интеграция с off-chain источниками.
class EventIndexer {
private db: Pool;
private provider: JsonRpcProvider;
private processorMap: Map<string, EventProcessor> = new Map();
async indexFromBlock(startBlock: number): Promise<void> {
let currentBlock = startBlock;
const headBlock = await this.provider.getBlockNumber();
while (currentBlock <= headBlock) {
const batch = Math.min(currentBlock + 999, headBlock);
const logs = await this.provider.getLogs({
fromBlock: currentBlock,
toBlock: batch,
address: CONTRACT_ADDRESSES,
});
await this.db.query('BEGIN');
try {
for (const log of logs) {
await this.processLog(log);
}
await this.updateCursor(batch);
await this.db.query('COMMIT');
} catch (e) {
await this.db.query('ROLLBACK');
throw e;
}
currentBlock = batch + 1;
}
// После initial sync переходим на real-time
await this.startRealtimeIndexing(headBlock);
}
private async startRealtimeIndexing(fromBlock: number): Promise<void> {
// WebSocket подписка на новые блоки
const wsProvider = new WebSocketProvider(process.env.WS_RPC_URL!);
wsProvider.on('block', async (blockNumber: number) => {
const logs = await this.provider.getLogs({
fromBlock: blockNumber,
toBlock: blockNumber,
address: CONTRACT_ADDRESSES,
});
for (const log of logs) {
await this.processLog(log);
}
await this.updateCursor(blockNumber);
});
}
}
Ключевые принципы кастомного индексера:
- Cursor-based resumption — храним последний обработанный блок в БД, рестарт продолжается с этой точки
- Транзакционность — обработка блока в SQL транзакции: либо все события блока записаны, либо ни одно
-
Idempotency — повторная обработка одного блока не создаёт дубликатов (
ON CONFLICT DO NOTHING) - Reorg handling — реорганизации блокчейна реальны. Нужен механизм отката последних N блоков при обнаружении reorg
Event Processing Pipeline
Для высоконагруженных систем — Kafka как шина событий:
Blockchain Listener → Kafka Topics → Event Processors → PostgreSQL
↓
Notification Service (WebSocket/Webhook)
↓
Analytics (ClickHouse)
Разделение listener и processor даёт горизонтальное масштабирование и устойчивость к сбоям: если processor упал, Kafka хранит события, при восстановлении — обработка продолжится с offset.
Мониторинг инфраструктуры
Prometheus + Grafana — стандартный стек. Ключевые метрики:
// Пример метрик для индексера
const metrics = {
// Отставание от head блока
indexerLag: new Gauge({ name: 'indexer_lag_blocks', help: '...' }),
// Скорость обработки событий
eventsPerSecond: new Counter({ name: 'events_processed_total', help: '...' }),
// Ошибки RPC
rpcErrors: new Counter({ name: 'rpc_errors_total',
labelNames: ['method', 'error_type'] }),
// Время обработки блока
blockProcessingTime: new Histogram({
name: 'block_processing_seconds',
buckets: [0.1, 0.5, 1, 5, 10]
}),
};
Алерты:
-
indexer_lag_blocks > 100→ critical (индексер не успевает) -
rpc_errors_total rate > 10/min→ warning (проблемы с RPC) -
block_processing_seconds > 30→ warning (медленная обработка)
Управление ключами и секретами
Для production инфраструктуры — разграничение полномочий:
- Read-only ключи (для индексеров, API): доступ только к чтению on-chain данных
- Transaction signing keys (для ботов, автоматизации): минимальные права, хранятся в AWS KMS или HashiCorp Vault
- Admin keys (multisig Gnosis Safe): только для управления контрактами, никогда в автоматизации
- Rotation — ротация API ключей RPC провайдеров каждые 90 дней
Типовые этапы проекта
| Фаза | Содержание | Срок |
|---|---|---|
| Assessment | Анализ требований, выбор архитектуры | 1–3 дня |
| Node setup | Нода / RPC конфигурация, мультиплексирование | 3–5 дней |
| Indexer | Subgraph или кастомный индексер | 1–2 недели |
| Event pipeline | Kafka/Redis, processors, webhooks | 3–5 дней |
| Monitoring | Prometheus + Grafana + алерты | 2–3 дня |
| Load testing | Нагрузочное тестирование, оптимизация | 2–3 дня |
| Documentation | Runbook, incident response | 1–2 дня |
Суммарно для типичного DeFi протокола — 3–6 недель от требований до production-ready инфраструктуры с мониторингом и документацией.







