Все записи

10 мин чтения

Как построить продукт на шлюзе Label 309

Шлюз Label 309 — это публикующий движок за продуктом Proof of Existence: он берёт на себя отправку транзакций в Cardano, хранилище, балансы, индексацию и webhook'и, чтобы ваш продукт мог отвечать за пользовательский опыт.

Чтобы добавить функцию Proof of Existence, не запуская собственный блокчейн, вы строите продукт на шлюзе. Шлюз Label 309 — это публикующий движок за продуктом Proof of Existence: он выполняет всю тяжёлую операционную работу — расчёты стоимости, загрузки, отправку транзакций в Cardano, подтверждение, обработку реоргов, индексацию записей, балансы счетов, финансирование хранилища, API-ключи и webhook'и — и предоставляет всё это по обычному HTTP. Ваш продукт вызывает эти эндпоинты и владеет всем, что на самом деле видят пользователи: интерфейсом, биллинговыми отношениями, предметным рабочим процессом и брендом.

Ядро шлюза открыто, а CardanoWall — это эталонный продукт, построенный на нём. Полезное для разработчиков здесь в том, что никакого закрытого входа нет: CardanoWall обращается к шлюзу через те же публичные эндпоинты, что и вы, поэтому любой подход, работающий для эталонного продукта, работает и для вас.

Кому стоит строить продукт на шлюзе?

Стройте на шлюзе, если вам нужен Proof of Existence внутри продукта, а не как ручное действие, которое пользователь выполняет на сайте.

Хорошо подходят:

  • продукты для нотариального заверения документов;
  • архивы доказательств для комплаенса;
  • платформы для установления происхождения данных ИИ и управления датасетами;
  • системы подтверждений для непрерывной интеграции;
  • инструменты для работы с юридическими доказательствами;
  • порталы зашифрованного раскрытия информации;
  • сервисы проверки подлинности медиа;
  • внутренние корпоративные инструменты аудита;
  • страницы подтверждений для издателей.

Во всех этих случаях пользователи не хотят думать о построении транзакций Cardano, финансировании UTxO, кредитах на хранилище или подтверждениях в блокчейне. Им нужен рабочий процесс, который выдаёт долговечные, проверяемые подтверждения. Шлюз делает такой процесс возможным, не превращая вашу команду в операторов инфраструктуры Cardano.

Что принадлежит шлюзу, а что — вашему продукту?

Разделение и есть вся суть, поэтому стоит сказать о нём прямо. Шлюз владеет базовым слоем — конвейером публикации и всем состоянием денег, блокчейна и хранилища за ним:

  • расчёт стоимости, загрузка и публикация;
  • построение, отправка, подтверждение транзакций Cardano, обработка реоргов и возвраты при окончательной неудаче;
  • загрузка содержимого и шифротекста в хранилище, а также финансирование хранилища, которое за этим стоит;
  • общий индекс записей в блокчейне, охватывающий каждую запись Label 309 в сети;
  • балансы счетов и записи в книге, которые их изменяют;
  • валютное ценообразование и наценки;
  • учётные данные API и доставка webhook'ов.

Это инфраструктурная работа. В продакшене она должна быть точной, наблюдаемой и скучной. Вашему приложению не следует реализовывать её заново, если только запуск шлюза не является вашей непосредственной задачей — а если это так, см. запуск собственного шлюза.

Ваш продукт владеет слоем вендора — всем, что относится к стороне поставщика:

  • учётные записи и сессии пользователей;
  • онбординг и биллинг;
  • права доступа в продукте;
  • ваш интерфейс и ваши письма;
  • цены, которые вы показываете клиентам;
  • предметные понятия, такие как «дело», «релиз», «датасет» или «пакет доказательств»;
  • read-модели, построенные на событиях шлюза;
  • процессы поддержки.

Шлюзу не нужно знать, что подтверждение относится к судебному иску, прогону обучения модели, ежеквартальному пакету для комплаенса или выпуску журнала. Ему нужно лишь публиковать корректные записи Label 309 и поддерживать операционное состояние вокруг них. Это разделение делает обе системы чище: ваш продукт можно перестроить или ребрендировать, не трогая состояние блокчейна или денег, а шлюз можно обновить, не зная, что ваш продукт вообще существует.

Как вызывать слой данных от имени пользователя?

Слой данных (/api/v1/*) — это API для работы со счётом. Используйте его всякий раз, когда действие происходит от имени пользователя или счёта:

  • рассчитать стоимость публикации;
  • загрузить содержимое или шифротекст;
  • опубликовать запись;
  • прочитать баланс или книгу счёта;
  • получить список, загрузить или проверить публичные записи;
  • зарегистрировать webhook'и в рамках счёта.

В продукте-обёртке ваш бэкенд выпускает короткоживущий токен счёта для счёта пользователя в шлюзе, а клиент вызывает слой данных только с теми областями доступа, которые ему нужны. Области доступа и есть граница прав: экрану публикации нужен poe:create, виджету баланса нужен account:read, а эндпоинтам публичных записей не нужны никакие учётные данные вовсе — они обслуживают анонимные запросы, и именно это делает индекс общественным благом, а не представлением для отдельного клиента.

Токены по замыслу короткоживущие (по умолчанию один час). Выпускайте один на сессию и перевыпускайте по истечении срока, чтобы утёкший токен был проблемой на один час, а не инцидентом. И никогда не отправляйте операторские учётные данные в браузер — это единственное правило, ради защиты которого существует следующий раздел.

Как вызывать слой управления в роли оператора?

Слой управления (/control/v1/*) предназначен только для доверенных бэкендов и операторов. Используйте его, чтобы:

  • создавать счета в шлюзе, а также включать или отключать их;
  • применять корректировки книги после того, как ваша биллинговая система получила деньги;
  • задавать наценки для каждого счёта;
  • выпускать токены счёта и API-ключи;
  • регистрировать операторский firehose webhook'ов;
  • регистрировать кошельки и источники финансирования хранилища и управлять ими;
  • читать аудиторское и операционное состояние.

Этот слой живёт за вашим бэкендом. Относитесь к операторским учётным данным как к продакшен-секретам с полномочиями тратить деньги — потому что они их имеют. Короткоживущий операторский токен (по умолчанию 24 часа) обслуживает повседневное администрирование; единственный корневой секрет, хранящийся в хранилище секретов, зарезервирован для тех немногих операций, что регистрируют кошельки и источники хранилища.

Слой управления — это то, как ваша биллинговая система и предоплаченный баланс шлюза остаются связанными. Платёж проходит успешно в вашей системе, и затем ваш бэкенд применяет одну идемпотентную корректировку книги к счёту в шлюзе. Это и есть весь механизм пополнения целиком, и следующие два раздела объясняют, почему он устроен именно так.

Почему не стоит запрашивать таблицы шлюза напрямую?

Потому что контрактом является не схема, а HTTP API и webhook'и.

Движок шлюза владеет собственными схемами Postgres (cw_core и cw_api). Вашему продукту не следует читать или писать их, даже когда обе системы используют один экземпляр Postgres. Сосуществование схем — это поддерживаемая форма развёртывания, но границей является схема, а не база данных: эти схемы движка внутренние и могут меняться без предупреждения, тогда как HTTP-слои и firehose стабильны. Если вы перешагнёте через эту границу, рутинное обновление шлюза может незаметно сломать ваш продукт.

Если вам нужны данные, которые API не предоставляет, считайте это пробелом в API, о котором стоит сообщить, а не разрешением выполнять join по схемам.

Как строить собственные экраны на событиях шлюза?

Каждому продукту нужны собственные представления: отправленные записи, история клиентов, балансы, неудачи публикации, хронологии дел, пакеты доказательств, дашборды аудита. Не стройте их, опрашивая каждую строку или делая join во внутренности шлюза.

Вместо этого зарегистрируйте webhook'и и проецируйте события в собственные таблицы. Шлюз предоставляет операторский firehose — каждое событие жизненного цикла на экземпляре — плюс подписки на webhook'и в рамках счёта для более узких процессов. Представление «отправленные» — канонический пример: потребляйте события статуса публикации, проецируйте их в собственную таблицу и отрисовывайте из неё.

Доставка происходит как минимум один раз, поэтому делайте проекцию идемпотентной. Практичная read-модель может использовать в качестве ключа:

  • идентификатор события или идентификатор доставки (чтобы повторная доставка была no-op);
  • идентификатор записи в шлюзе;
  • итоговый хеш транзакции;
  • ваш собственный идентификатор пользователя;
  • идентификатор вашего собственного предметного объекта;
  • статус и метки времени.

Затем ваш интерфейс отрисовывает из собственных таблиц, а шлюз остаётся авторитетом по тратам, жизненному циклу публикации и фактам блокчейна. Каждая доставка подписана; проверьте подпись и обеспечьте окно допуска по метке времени, прежде чем доверять событию.

Как должны двигаться деньги между вашим биллингом и шлюзом?

Держите модель простой: баланс шлюза — это расходуемый баланс, а ваша биллинговая система — лишь один из способов, которым деньги попадают на него.

Ваша платёжная система может собирать оплату с карт, по счетам, в криптовалюте, ручными корпоративными кредитами или грантами. Шлюзу не нужно ничего об этом знать. Чистая схема такая:

  1. Ваша биллинговая система подтверждает платёж.
  2. Ваш бэкенд применяет одну идемпотентную корректировку книги к счёту в шлюзе, привязанную к идентификатору платежа.
  3. Баланс шлюза увеличивается.
  4. Будущие операции публикации и загрузки списывают с этого баланса.
  5. Если публикация окончательно проваливается, шлюз сам отменяет списание.

Отсюда следуют два вывода. Во-первых, идемпотентность важна, потому что биллинговые конвейеры доставляют как минимум один раз: передавайте собственный идентификатор платежа как ссылку корректировки, и пять доставок одного платежа пополнят баланс один раз. Во-вторых, не зеркальте книгу шлюза в собственную таблицу и не считайте зеркало истиной для решений о тратах — кэшируйте его для отрисовки, если нужно, но читайте шлюз всякий раз, когда решение реально двигает деньги. Поскольку шлюз сам выполняет возвраты, вам также не следует строить возвратный путь на стороне вендора для неудач публикации; это привело бы к двойному возврату.

Где должен жить каждый вид ключей?

Шлюзу никогда не должен требоваться Identity Seed пользователя. Клиент или SDK может хешировать содержимое, шифровать запечатанные данные и подписывать записи локально; шлюз лишь публикует байты финализированной записи и отправляет транзакцию Cardano. (О том, почему эта граница важна от края до края, см. почему ключи никогда не покидают устройство.)

В полноценной интеграции есть несколько различных классов ключей, и ошибка, которой нужно избежать, — это свести их в один «API-секрет». У них очень разный радиус поражения:

  • Identity Seed пользователей и приватные ключи получателей — криптографическая идентичность пользователя, место которой на устройстве;
  • ключи подписи записей, производные от этой идентичности;
  • API-ключи счёта и короткоживущие токены счёта — место которых в контексте продукта или клиента, которому они нужны;
  • операторские токены и корневой секрет — место которых только на доверенных бэкендах;
  • собственные ключи подписи Cardano и хранилища шлюза, а также его секреты подписи webhook'ов — место которых в связке ключей шлюза.

Сопоставьте каждый класс с наименьшим местом, способным его удержать, и единичная утечка останется ограниченной.

Когда стоит развернуть шлюз самостоятельно, а не пользоваться размещённым?

Разворачивайте сами, когда операционная независимость важнее удобства.

Размещённый шлюз — простейший путь для большинства интеграций: вы публикуете через готовый сервис по стандартным API-поверхностям и никогда сами не выполняете операции с блокчейном или хранилищем. Самостоятельное размещение меняет эту простоту на контроль — собственное финансирование кошелька Cardano, собственное финансирование хранилища, собственные операторские политики, собственная доступность и сетевые зависимости, собственные наценки, собственная граница комплаенса и отсутствие зависимости от третьей стороны при публикации.

Но контроль — это ещё и ответственность. Самостоятельное размещение означает, что вы финансируете ADA и кредиты на хранилище, защищаете связку ключей, эксплуатируете Postgres, мониторите провайдеров блокчейна, делаете резервные копии, ротируете учётные данные, управляете webhook'ами и реагируете на инциденты. Оно убирает зависимость от вендора; оно не убирает операционную работу. Запуск собственного шлюза разбирает, что это на самом деле влечёт за собой.

Что должны видеть ваши пользователи в подтверждении?

Большинство пользователей должны прежде всего видеть понятия вашего продукта. Их волнует «опубликовать доказательство», «запечатать этот файл», «подтвердить этот снимок датасета» или «закрепить этот релиз». Им не должно приходиться читать спецификацию метаданных, чтобы пользоваться продуктом.

И всё же каждое представление подтверждения должно раскрывать факты, которые делают утверждение независимо проверяемым:

  • хеш транзакции;
  • время блока и статус подтверждения;
  • алгоритм хеширования и дайджест;
  • открытый ключ подписавшего, когда запись подписана;
  • URI хранилища, когда они есть;
  • статус запечатанного получателя, когда это уместно;
  • корень Merkle и доказательство листа, когда запись пакетирует много файлов;
  • сам вердикт проверки.

Именно так продукт остаётся приятным в использовании, не пряча криптографическое утверждение под ним.

Как не привязать продукт к одному шлюзу?

Шлюз помогает вам публиковать; он никогда не должен становиться подтверждением.

Запись в блокчейне — это метаданные Label 309, а проверка спроектирована так, чтобы работать всего из трёх входных данных: метаданных транзакции, опционально байтов содержимого и публичного обозревателя блокчейна Cardano — а ключи получателя добавляются лишь для того, чтобы расшифровать запечатанные записи. В этом пути доверия нет сервера издателя. Если ваш шлюз завтра исчезнет, действительная запись всё равно должна проверяться независимыми инструментами. Стоит также помнить, что́ подобное подтверждение утверждает, а чего — нет: оно показывает, что именно эти байты существовали к определённому публичному моменту, а не что какое-либо утверждение о них истинно, что они кому-то принадлежат или что они авторизованы.

Стройте продукт вокруг этого обещания:

  • надёжно храните хеши транзакций;
  • позволяйте пользователям экспортировать отчёты о проверке и скачивать пакеты доказательств;
  • сохраняйте списки листьев Merkle и их доказательства;
  • документируйте, как проверить запись вне вашего интерфейса;
  • избегайте приватных полей, которые может интерпретировать только ваш бэкенд.

Это и есть разница между «у нас есть строка в базе данных» и «мы выдали подтверждение, которое каждый может проверить».

Что почитать дальше

gatewayapidevelopers