Смарт-контракты и dApps: архитектура, стандарты и разработка
Связь с предыдущими темами курса
Ранее мы разобрали:
как данные попадают в блокчейн через транзакции и блоки
почему хэши, подписи и Merkle-деревья делают подмену заметной
как консенсус (PoW/PoS) и комиссии стимулируют честное поведениеТеперь логичный следующий шаг: понять, как поверх этих механизмов строятся программы, которые живут в блокчейне и выполняются по правилам сети. Это и есть смарт-контракты и dApps.
Что такое смарт-контракт
Смарт-контракт — это программа, размещённая в блокчейне, которая:
хранит данные (своё состояние)
принимает вызовы через транзакции
выполняет код одинаково на всех узлах
меняет состояние сети строго по правилам протоколаВажно: смарт-контракт не «умный» сам по себе. Он детерминированный: при одинаковом входе и одинаковом состоянии он должен давать одинаковый результат на всех узлах. Именно так сеть может прийти к одному итогу.
Источник для общего понимания: Документация Ethereum: Smart contracts.
Чем смарт-контракт отличается от обычного серверного кода
| Характеристика | Обычный сервер | Смарт-контракт |
|---|---|---|
| Кто исполняет код | Один владелец сервера | Сеть узлов по правилам протокола |
| Можно ли “починить на лету” | Обычно да | Обычно нет, код трудно менять |
| Стоимость выполнения | Платит владелец сервера | Платит отправитель транзакции (комиссия) |
| Доступ к внешнему миру | Прямой (HTTP, базы данных) | Прямого нет, только данные блокчейна |
Модель работы: транзакция вызывает код
В предыдущих темах транзакция была “сообщением об изменении”. В мире смарт-контрактов это выглядит так:
Пользователь подписывает транзакцию в кошельке.
Транзакция содержит адрес контракта и данные вызова (какую функцию вызвать и с какими параметрами).
Узлы исполняют код контракта.
Если выполнение корректное и комиссия оплачена, состояние обновляется и попадает в новый блок.!Как транзакция приводит к выполнению смарт-контракта и изменению состояния
Базовые понятия, без которых нельзя писать dApps
Адрес и аккаунт
Адрес — короткий идентификатор в сети, на который можно отправлять транзакции и активы.
Во многих сетях со смарт-контрактами есть два типа аккаунтов:
аккаунт пользователя — управляется приватным ключом (подписью)
аккаунт контракта — управляется кодом контрактаПользовательский аккаунт может вызвать контракт, а контракт может вызывать другие контракты.
Состояние контракта
Состояние — данные, которые контракт хранит “внутри себя” в блокчейне.
Примеры состояния:
балансы токена
список владельцев NFT
параметры протокола (комиссии, роли)Ключевая идея: состояние контракта обновляется только при успешной транзакции.
Газ и комиссия
Чтобы сеть не утонула в бесконечных вычислениях, выполнение кода ограничивают через газ.
Газ — это единицы “стоимости вычислений”, которые нужны для выполнения операций контракта.
Практический смысл:
сложнее вычисления и больше запись в состояние — больше газа
пользователь платит комиссию, чтобы покрыть газ
если газа не хватило, выполнение откатывается (состояние не меняется), но комиссия за попытку обычно всё равно списываетсяОфициальное введение: Документация Ethereum: Gas and fees.
ABI: как фронтенд “разговаривает” с контрактом
ABI (Application Binary Interface) — это описание функций и событий контракта в стандартизированном формате.
Зачем нужно ABI:
фронтенд знает, как сформировать данные вызова функции
библиотека (например, ethers.js) может декодировать ответы и событияЕсли совсем просто: ABI — это “словарь”, который объясняет, как правильно вызвать контракт.
Справка: Документация Solidity: ABI specification.
События (events) и логи
Событие — это запись в логах транзакции, которую контракт может “опубликовать” во время выполнения.
Зачем события используют в dApps:
события удобны для поиска истории действий (кто, что, когда сделал)
события проще индексировать внешними сервисамиВажно: логи отличаются от состояния.
состояние — это то, что контракт хранит и может читать внутри себя
логи — это “след выполнения”, который удобно читать снаружиЧто такое dApp и из чего она состоит
dApp (decentralized application) — это приложение, где ключевая бизнес-логика и права доступа закреплены в смарт-контрактах, а пользователь взаимодействует с ними через интерфейс.
Типичная архитектура dApp:
смарт-контракты — правила и активы
фронтенд — сайт/мобильное приложение
кошелёк — инструмент подписи транзакций (например, расширение браузера)
RPC-провайдер — узел или сервис, через который фронтенд отправляет запросы в сеть
индексатор — сервис, который ускоряет поиск по событиям и истории
оракул — механизм доставки внешних данных в блокчейн (если нужно)!Типовая архитектура dApp и роли компонентов
Зачем нужен индексатор
Блокчейн — не база данных для удобных запросов “покажи все операции пользователя за год”. Чтение исторических данных напрямую может быть медленным и дорогим.
Индексатор — это внешний сервис, который:
читает блоки и события
строит удобные таблицы и API
отдаёт фронтенду быстрые ответыПопулярный подход — использовать готовые решения или писать свой индексатор. Пример экосистемы: The Graph documentation.
Зачем нужен оракул
Смарт-контракт сам по себе не может безопасно “сходить в интернет” и проверить курс доллара или счёт матча. Причина простая: разные узлы увидят разные ответы, и консенсус сломается.
Оракул — это механизм, который доставляет внешние данные в блокчейн так, чтобы сеть могла согласованно их использовать.
Ключевой риск: если источник данных нечестный, контракт примет неверные решения. Поэтому оракулы — отдельная большая тема безопасности.
Стандарты токенов: почему без них dApps не совместимы
Стандарт — это соглашение о том, какие функции и события должен иметь контракт, чтобы кошельки, биржи и другие приложения умели с ним работать.
В Ethereum стандарты публикуются как EIP.
ERC-20: взаимозаменяемые токены
ERC-20 обычно используют для “обычных” токенов, где все единицы одинаковые.
Идея стандарта:
есть функция проверки баланса
есть перевод токенов
есть механизм разрешений “разрешаю контракту тратить мои токены”Источник: EIP-20: ERC-20 Token Standard.
ERC-721: уникальные токены (NFT)
ERC-721 — стандарт для NFT, где каждый токен уникален и имеет свой идентификатор.
Зачем это нужно:
право собственности на конкретный уникальный токен
совместимость с маркетплейсами и кошелькамиИсточник: EIP-721: ERC-721 Non-Fungible Token Standard.
ERC-1155: много токенов в одном контракте
ERC-1155 позволяет хранить сразу “наборы” токенов разных типов в одном контракте.
Практическая польза:
экономия газа при массовых операциях
удобно для игр и коллекцийИсточник: EIP-1155: Multi Token Standard.
Как выбрать стандарт
| Сценарий | Обычно выбирают |
|---|---|
| Валюта приложения, баллы, governance-токен | ERC-20 |
| Коллекция уникальных предметов | ERC-721 |
| Игра с множеством типов предметов и партиями | ERC-1155 |
Разработка смарт-контрактов: минимальный жизненный цикл
Ниже — практичный, “инженерный” процесс разработки.
Проектирование
Сначала фиксируют требования:
какие действия должен уметь делать пользователь
какие роли существуют (владелец, админ, любой)
какие данные нужно хранить в состоянии
какие события нужно публиковать для фронтендаПолезная привычка: формулировать правила как “контракт обязан запрещать X и разрешать Y”.
Реализация на Solidity
В экосистеме Ethereum самый распространённый язык — Solidity.
Справка: Документация Solidity.
Важно: в реальной разработке почти всегда используют проверенные библиотеки, чтобы не изобретать заново то, что уже много раз ломали.
Пример стандартных реализаций: OpenZeppelin Contracts.
Компиляция и деплой
После написания код:
компилируют (получают байткод)
отправляют транзакцию “создания контракта”
получают адрес контракта в сетиТестирование
Тесты проверяют два слоя:
что логика работает в нормальных сценариях
что защита держит плохие сценарии (не тот пользователь, неверные данные, попытка обмана)В смарт-контрактах тестирование особенно важно, потому что ошибки часто стоят денег и репутации.
Верификация кода
Частая практика — публиковать исходники контракта в обозревателе блоков, чтобы любой мог убедиться, что байткод соответствует исходному коду.
Пример сервиса: Etherscan.
Типовые уязвимости и как о них думать
Ниже — базовые риски, которые нужно понимать ещё до “профи-уровня”.
Reentrancy: повторный вход
Суть: контракт отправляет внешнему контракту активы или делает внешний вызов, а внешний контракт вызывает его обратно “раньше времени”, пока внутреннее состояние ещё не приведено в порядок.
Базовая защита на уровне мышления:
сначала обновляй состояние, потом делай внешние вызовы
используй готовые защитные примитивы из библиотекСправка от OpenZeppelin: OpenZeppelin: ReentrancyGuard.
Контроль доступа
Самая частая ошибка: функция, которая должна быть доступна только администратору, случайно доступна всем.
Практическая рекомендация:
явно описывай роли
тестируй “кто угодно не может сделать X”Переполнения и безопасная математика
В современных версиях Solidity многие переполнения целых чисел проверяются автоматически, но понимать риск всё равно полезно.
Front-running и MEV (очень кратко)
Поскольку транзакции часто видны в очереди до включения в блок, кто-то может попытаться вставить свою транзакцию раньше и получить выгоду.
Простая интуиция:
если логика зависит от “кто первый”, её могут атаковать
аукционы, DEX и ликвидации особенно чувствительныОбновляемость контрактов: почему это сложно
Код контракта в блокчейне обычно неизменяем. Но продуктам нужны обновления. Отсюда появляются паттерны апгрейда.
Прокси-паттерн (интуитивно)
Идея:
прокси-контракт хранит состояние и принимает вызовы
он перенаправляет вызовы в контракт-реализацию с логикой
адрес реализации можно поменять, получив “обновление” логикиГлавные риски:
ошибка в правах на апгрейд превращается в полный захват
несовместимость хранения данных (storage layout) ломает состояние!Как работает прокси-апгрейд и почему состояние хранится в прокси
Практическая отправная точка: OpenZeppelin: Upgrades.
Практический чек-лист перед запуском dApp
Проверь контроль доступа для критичных функций.
Покрой тестами основные сценарии и запреты.
Продумай события: фронтенду проще жить на логах.
Оцени угрозы front-running, если есть “гонка” транзакций.
Используй проверенные библиотеки (например, OpenZeppelin) вместо самописной криптологии.
Если контракт обновляемый, отдельно проверь права апгрейда и совместимость хранения.Главное, что нужно запомнить
Смарт-контракт — детерминированный код в блокчейне, который меняет состояние через транзакции.
dApp почти всегда состоит из контрактов + фронтенда + кошелька + RPC, часто дополняется индексатором и оракулом.
Газ и комиссии ограничивают вычисления и защищают сеть от спама.
ABI и события — основа связи “контракт ↔ интерфейс”.
Стандарты ERC (ERC-20, ERC-721, ERC-1155) дают совместимость токенов с экосистемой.
Безопасность — не опция: ошибки в контрактах трудно исправлять, поэтому тесты и аудит критичны.Мини-словарь
| Термин | Простое объяснение |
|---|---|
| Смарт-контракт | Программа в блокчейне, исполняемая сетью |
| dApp | Приложение, где ключевая логика закреплена в смарт-контрактах |
| Газ | Мера стоимости вычислений для выполнения контракта |
| ABI | Описание, как вызывать функции контракта |
| Событие (event) | Лог-запись, удобная для чтения и индексации |
| Индексатор | Внешний сервис для быстрых запросов по истории и событиям |
| Оракул | Доставка внешних данных в блокчейн |
| ERC-20 | Стандарт взаимозаменяемых токенов |
| ERC-721 | Стандарт NFT |
| ERC-1155 | Стандарт набора разных токенов в одном контракте |