Что такое dApp: фронтенд без бэкенда

Чем фронтенд блокчейн-приложения отличается от обычного веб-сайта и почему у него нет привычного бэкенда.

dApp (decentralized application) — приложение, чья бизнес-логика и данные живут в смарт-контрактах на блокчейне, а фронтенд — это обычный веб-интерфейс, который читает и пишет в эти контракты напрямую.

Если вы умеете делать сайты на React и звать REST API — вы уже на 80% готовы делать dApp. Меняется одна, но фундаментальная вещь: куда уходят запросы. В классическом вебе фронт стучится в ваш сервер (бэкенд), тот лезет в базу, проверяет права, считает бизнес-логику и возвращает JSON. В Web3 роль «сервера + базы + бизнес-логики» играет смарт-контракт в блокчейне, а фронт общается с ним через узел сети (ноду).

Зачем вообще так делать

Главная идея — отсутствие единой точки доверия и контроля. У обычного сервиса есть владелец: он может изменить правила, забанить пользователя, потерять базу, закрыться. У dApp правила записаны в контракт, который после деплоя нельзя втихую переписать, а данные хранит сеть из тысяч независимых узлов. Это полезно там, где важны прозрачность и отсутствие посредника: деньги (DeFi), владение (NFT, токены), голосования (DAO).

Расплата за это — другая модель работы. Записать данные в блокчейн стоит денег (комиссия за газ), операция занимает секунды, а не миллисекунды, и её нельзя отменить. Поэтому фронтенд dApp должен честно показывать пользователю, что происходит: «транзакция отправлена», «ждём подтверждения», «готово».

Из чего состоит dApp

Минимальный dApp — это три слоя:

  • Фронтенд — обычный SPA (React/Vue/Svelte), статика. Часто хостится даже не на сервере, а на IPFS или Vercel — ему не нужен свой бэкенд.
  • Кошелёк — расширение браузера (MetaMask) или мобильное приложение. Хранит приватные ключи пользователя и подписывает транзакции. Фронт никогда не видит приватный ключ.
  • Смарт-контракт — программа на Solidity, задеплоенная в блокчейн. Это и есть «бэкенд» с логикой и состоянием.

Связующее звено — провайдер: соединение с узлом сети (через библиотеку вроде ethers.js), по которому фронт читает данные и отправляет подписанные транзакции.

Как работает под капотом

Поток данных в dApp при простом чтении выглядит так:

Браузер (React) --> ethers.js --> JSON-RPC --> нода блокчейна --> состояние контракта
       <--          <--         <--          <--

А при записи добавляется кошелёк, потому что транзакцию надо подписать приватным ключом, который есть только у него:

Фронт просит подпись --> Кошелёк (MetaMask) показывает окно --> Пользователь жмёт Confirm
   --> подписанная транзакция --> нода --> попадает в блок --> контракт меняет состояние

Заметьте: фронт не «вызывает функцию контракта» напрямую. Он формирует JSON-RPC-запрос с закодированными данными вызова, отправляет его узлу, а узел уже исполняет контракт на виртуальной машине Ethereum (EVM).

Частые ошибки новичка

  • Думать, что нужен свой бэкенд. Для базового dApp сервер не нужен вообще: чтение и запись идут напрямую в контракт через ноду.
  • Хранить приватные ключи на фронте. Никогда. Ключи — только в кошельке пользователя; фронт лишь просит подпись.
  • Считать запись мгновенной. Транзакция подтверждается секундами и стоит газ; интерфейс обязан показывать состояние ожидания.

Итоги

  • dApp = обычный фронтенд + кошелёк + смарт-контракт вместо привычного «сервер + база».
  • Бизнес-логику и данные держит контракт в блокчейне; фронт читает и пишет в него напрямую.
  • Запись стоит денег, идёт секундами и необратима — это диктует особый UX.
  • Приватные ключи живут только в кошельке; фронт получает подпись, но не ключ.
Проверьте себя
1. Что в dApp играет роль «бэкенда с логикой и базой данных»?
AСвой Node.js-сервер
BСмарт-контракт в блокчейне
CРасширение MetaMask
DIPFS-хранилище
2. Где в dApp хранятся приватные ключи пользователя?
AВ localStorage фронтенда
BНа сервере проекта
CВ кошельке (например, MetaMask)
DВ смарт-контракте
3. Почему интерфейс dApp обязан показывать состояние «ожидание»?
AТак требует ESLint
BЗапись в блокчейн занимает время и стоит газ
CЧтобы скрыть приватный ключ
DИз-за ограничений React