Chainlink Functions — это сервис офчейн-вычислений по запросу: ваш смарт-контракт отправляет задание (пакет параметров + фрагмент JavaScript-кода), децентрализованная сеть оракулов (DON) исполняет этот код, получает данные из внешних API, формирует результат и возвращает его ончейн через координатор/роутер. Модель «запрос-ответ» позволяет подключать произвольные Web2-источники и агрегировать их в проверяемый для контракта результат.
Ключевая идея: логика получения/агрегации данных исполняется вне блокчейна, а контракт получает компактный итог (число, строку, структуру) и может на его основе принимать решения: разблокировать функцию, установить параметр, инициировать своп/депозит и т. п.
Chainlink Functions
- Functions = офчейн-код + API → проверяемая доставка результата ончейн для вашего контракта.
- Архитектура: Consumer (ваш контракт) ↔ Router/Coordinator ↔ DON (оракулы-исполнители).
- Для цен/триггеров высокой частоты комбинируйте с Data Streams; для сообщений/переводов между сетями — с CCIP.
- Безопасность держится на шифровании секретов, валидации отправителя, идемпотентности результата и SLA по задержке (см. Идемпотентность, SLA: P95/P99).
- Типовые кейсы: агрегация нескольких API, проверка условий перед ончейн-действием, оркестрация «программируемых переводов», KYC/allowlist-проверки по внешним реестрам (без раскрытия приватных ключей).
Где Functions уместны, а где лучше альтернативы
| Задача | Лучше Functions | Лучше другой сервис |
|---|---|---|
| Получить данные из нескольких Web2-API, агрегировать, вернуть метрику | ✓ | — |
| Проверяемая случайность | — | Chainlink VRF |
| Низкая задержка цен для ликвидаций/триггеров | Частично (как pre-check) | Data Streams |
| Межсеть: сообщение/перевод актива + действие | В связке (pre/post-логика) | CCIP |
| Долгоживущие задачи/крон | В связке (триггеры) | Chainlink Automation/Keepers (см. интеграции инструментов) |
Вывод: Functions — гибкий офчейн-«клей» между Web2 и Web3. Для RNG, стриминга котировок и межсети есть специализированные строительные блоки.
Архитектура и роли
- Consumer (ваш контракт). Формирует и отправляет запрос; получает колбэк с результатом. Содержит бизнес-логику принятия решений.
- Router / Coordinator. Ончейн-контракты Chainlink, маршрутизирующие запросы к DON и вызывающие ваш колбэк по завершении.
- DON (децентрализованная сеть оракулов). Узлы исполняют предоставленный вами JS-код в изолированной среде, делают HTTP-запросы к внешним API, собирают и подписывают результат.
- Billing/подписка. Счёт для оплаты выполнения (как правило, subscription): контракт расходует средства за вычисления/доставку.
Высокоуровневый поток:
- Consumer вызывает метод запроса (через Router), передавая JS-код, аргументы и параметры исполнения.
- DON исполняет код: делает HTTP-запросы, агрегирует/валидирует ответы, формирует результат.
- DON возвращает пакет с результатом и метаданными; Router/Coordinator валидацией доставки инициирует ончейн-колбэк вашего контракта.
- Ваш контракт в колбэке проверяет контекст/идентификатор и применяет результат.
Модель «запрос-ответ»: параметры, которые важно спроектировать
| Параметр | Назначение | Подсказки |
|---|---|---|
| Код (JS) | Логика fetch/агрегации, валидации, нормализации данных | Держите код коротким и детерминированным |
| Args | Входные параметры (символы/суммы/диапазоны) | Включайте «подписи»/версию, чтобы отсекать устаревшие запросы |
| Secrets | Токены API/ключи | Используйте шифрование и «DON-секреты»; не логируйте секреты |
| Callback gas limit | Газ на колбэк Consumer | Заложите запас, не делайте тяжёлую логику в колбэке |
| Timeout/TTL | Срок годности результата | Отклоняйте опоздавшие ответы в Consumer |
| Don/Route | Выбор пула исполнителей/сети | Следуйте рекомендациям для целевой сети |
Практика: всё, что может меняться (версии источников, формулы агрегации), снабжайте version и описывайте в events — это упрощает аудит.
Секреты и безопасность источников
- Шифрование секретов. Ключи API/токены передаются в Functions зашифрованными и доступны только исполнителям DON.
- Изоляция JS-среды. Код исполняется в песочнице с предопределёнными библиотеками (HTTP-клиент, крипто, базовые утилиты).
- Список доменов (allow-list) на стороне провайдера. Исполнители ограничены разрешёнными направлениями — снижает риск утечек.
- Валидация в Consumer. Колбэк должен принимать вызовы только от Router/Coordinator.
- Идемпотентность результата. Один и тот же requestId → один эффект (см. Идемпотентность).
Не делайте: хранить секреты как аргументы, логировать токены, принимать колбэки от произвольных адресов.
Паттерны агрегации данных
- Мульти-источник, медиана/кворум. Запросить N независимых API, отбросить выбросы, вернуть медиану/усечённое среднее.
- Нормализация единиц. Приводите цены/поля к каноническому формату (десятичность, валюты, timestamp).
- Смешивание с ончейн-референсом. Сверять результат с ончейн-лентой (например, ценовой фид) и отклонять несогласованные значения. См. Ценовой оракул.
- Доверие по подписи. Приём данных только с подписью поставщика; проверка в JS + итоговая валидация в Consumer.
Анти-паттерны: единичный источник без подписи, слепая вера результату без sanity-порогов и дедлайнов.
Интеграция с другими строительными блоками Chainlink
- Data Streams. Используйте для «быстрых» триггеров; Functions — для пред-обработки/валидации и редких решений. Data Streams, Streams vs Feeds.
- CCIP. Оформляйте «перевод + действие»: Functions проверяет условие (KYC/лимит/цена), затем инициируется перевод/вызов через CCIP.
- VRF. Для честной случайности — только VRF. Functions не источник RNG.
- Interoperability. Компонуйте в системную межсеть: сообщения, активы (CCT), данные. Интероперабельность.
Безопасность Consumer-контракта
- Проверка отправителя. require(msg.sender == Router/Coordinator) в колбэке.
- Маппинг контекста. requestId → версия/параметры/инициатор/дедлайн.
- Идемпотентность. Повторная доставка = *no-op*; возвращайте прежний код результата. Идемпотентность
- Двухфазная логика. Сначала помечайте «ожидает результат», затем применяйте эффект; при сбое оставляйте состояние в безопасном виде.
- Лимиты. Per-tx/per-interval на чувствительные действия; если сценарий межсетевой — опирайтесь на allow-list маршрутов.
- Коды статуса и события. «Requested/Received/Executed/Expired/Rejected» — для отладки и поддержки.
SLA и эксплуатация (операционный профиль)
Отслеживайте:
- Latency P50/P95/P99 от запроса до «исполнено» (см. SLA по задержке).
- Success ratio (доля успешных ответов).
- Retry rate / duplicate hit rate (повторы и доля корректно пойманных повторов).
- Причины отказов: тайм-ауты, лимиты, валидация, газ колбэка.
Политики:
- TTL/deadline. Просроченные ответы отклонять в Consumer; не «принимать» данные после дедлайна.
- Rate limiting. На публичных эндпоинтах ограничивайте частоту вызовов, выполняйте exponential back-off.
- Алерты. SLO для P95/P99 и burn-rate — триггеры на деградации (см. SLA).
Стоимость и лимиты
| Компонент стоимости | Что влияет |
|---|---|
| Исполнение JS | Объём кода, число HTTP-вызовов, время ответа источников |
| Доставка ончейн | Газ колбэка и накладные на верификацию пакета |
| Подписка/баланс | Поддерживайте достаточный баланс для подписки; мониторьте расход |
Оптимизация: минимизируйте размер ответа (передавайте только то, что нужно контракту), объединяйте несколько значений в один результат, используйте медиану вместо полного набора сырых данных.
Типовые сценарии использования
- Ценовой pre-check перед свопом. Fetch из нескольких API → медиана → сравнение с ончейн-референсом → если расхождение < порога, разрешить своп.
- RWA-платёж/погашение. Проверить статус в реестре эмитента (подпись), вернуть агрегированный статус, инициировать действие в контракте.
- Access-контроль/allowlist. Проверка по внешней базе (с подписью) + ончейн-роль → открыть доступ к функции.
- Антифрод/скоринг. Не хранить фактические правила ончейн; вернуть «вердикт» и параметры лимита.
- Оркестрация межсети. Functions делает пред-валидацию (лимиты/цены/KYC), затем включает CCIP для перевода + действия.
Анти-паттерны
- Использовать Functions для случайности вместо VRF.
- Принимать колбэк от любого адреса.
- Отсутствие TTL/версий — «зомби-ответы» ломают инварианты.
- Единичный недоверенный источник данных без подписи/кворума.
- Тяжёлая бизнес-логика в колбэке Consumer → риски газа/отказов.
- Отсутствие идемпотентности и журналов requestId.
Дизайн payload и ответа
| Поле | Назначение |
|---|---|
| version | Версия логики/источников; защищает от устаревших ответов |
| requestedAt / deadline | Времена для SLA и TTL |
| sourceList | Какие API использованы (идентификаторы) |
| aggregate | Итоговая метрика/структура |
| proof/meta | Подписи поставщиков/хэши, если применимо |
| error | Код/сообщение об ошибке в случае сбоя |
Рекомендация: в контракт записывать хэш результата и статус; сырые детали — хранить off-chain для аудита.
Тест-план для интеграции
- Стабильные источники: один отвечает медленно/ошибкой — должен быть fallback без падения всего запроса.
- Дедлайн: проверить отказ по TTL и корректный UX.
- Повторы: дубликаты ответов по тому же requestId → *no-op*.
- Граница газа: искусственно занизить callbackGasLimit и убедиться, что колбэк не рушит состояние.
- Версии: отправить ответ со старой version — отказ.
- Нагрузочные тесты: серия параллельных запросов, мониторинг P95/P99.
Пример архитектурной сцепки (case)
Омничейн-депозит с защитой по цене:
- Functions собирает цены из 5 API, считает медиану, сравнивает с ончейн-фидом.
- Если расхождение ≤ 0.5% и deadline не истёк — контракт разрешает «перевод + действие» через CCIP (см. Programmatic Transfer).
- В противном случае — отказ с событием и кодом, без изменений состояния.
Плюсы: устойчивость к манипуляциям на одном источнике, контроль по SLA и дедлайну, семантическая атомарность.
Вопросы и ответы (FAQ)
Можно ли использовать любой внешний API? Да, если он разрешён конфигурацией провайдера (allow-list доменов) и не требует недопустимых библиотек. Секреты для авторизации передавайте шифрованными.
Кто платит за исполнение? Ваш subscription/счёт. Контроль расхода и пополнение — часть операционного контура.
Гарантируется ли время ответа? Нет жёстких гарантий; договаривайтесь через внутренние SLO и следите за P95/P99. Для критичных по времени решений комбинируйте с Data Streams.
Что делать при длительной деградации? Опустить лимиты, включить более жёсткие дедлайны, перевести сценарии в «только локальные решения» до восстановления (см. плейбуки SLA).
Можно ли «переиграть» ответ? Только отправив новый запрос; старый requestId должен оставаться идемпотентным.
Чек-лист внедрения
- Контракт проверяет отправителя колбэка и ведёт requestId → статус/версия/дедлайн.
- Реализована идемпотентность и двухфазная схема применения результата.
- Заданы TTL, sanity-чек диапазонов и «кворум» источников.
- Секреты передаются шифрованно; исключено логирование секретов.
- Настроены SLO/алерты: P95/P99, success ratio, retry/duplicate hit rate.
- Для межсети — интеграция с CCIP и политикой allow-list маршрутов.
- Документация событий/кодов статуса для фронта и саппорта.
