Перейти к содержанию

Ценовой оракул: свежесть данных и безопасный отказ

Целочисленный расчёт может быть безошибочным и всё же использовать слишком старый ответ. Поэтому библиотека должна определить временную допустимость feed до создания предложения. В уроке подготовим правило свежести и разберём границы отказа на управляемых данных.

Мы не читаем действительный блок и не измеряем heartbeat. Все временные значения ниже — условные секунды учебной шкалы. Результат — собственная политика для выбранного назначения; она не является универсальным maxAge для любого источника или сети.

Время ответа и время получения

Сервис получил JSON сейчас, но содержащаяся в нём котировка могла быть опубликована раньше. Время HTTP-ответа не становится временем обновления feed. Программа сохраняет необходимые сведения самого источника и контекст наблюдения сети. Иначе быстрый RPC способен сделать старую запись визуально «новой».

Также надо различать настенные часы сервера и предусмотренный временной контекст контрактной проверки. Для onchain-решения используются доступные программе условия сети; для серверной модели возможна своя процедура чтения и допустимого расхождения. В нашем учебном примере параметр now передаётся явно как часть контролируемого случая.

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

Политика допустимого ответа

Для ценового BTC/USD-источника библиотека требует положительный answer, ненулевое время обновления, отсутствие будущей даты относительно принятого now и возраст не больше своего maxAge. Ошибка чтения рассматривается отдельно. Другие feeds могут иметь другое допустимое содержание, поэтому правило положительного ответа не распространяем на технический sequencer feed.

// Самостоятельная модель политики, не готовый транспортный адаптер.
function requireFreshPrice({ answer, updatedAt, now, maxAge }) {
  if (answer <= 0n) throw new Error('Invalid price');
  if (maxAge < 0n || updatedAt <= 0n || updatedAt > now) throw new Error('Invalid time');
  if (now - updatedAt > maxAge) throw new Error('Stale price');
  return answer;
}

Входы здесь целые bigint в одинаковых временных единицах. Функция не устанавливает официальный адрес источника и не проверяет сетевое происхождение. До неё адаптер получает допустимую запись по определённой конфигурации. После неё арифметический слой может создать новое предложение.

Граница возраста

Пусть now равно 1 000, maxAge равно 120. Обновление в 940 имеет возраст 60 и принимается. Обновление в 880 имеет возраст ровно 120 и также принимается по выбранному условию. В 879 возраст равен 121, поэтому новый расчёт отвергается. Эти различия следуют из строгого сравнения >, а не из измеренного опыта.

Если продукт предпочитает исключить граничный момент, он изменяет правило явно и описывает новую область. Нельзя иметь одно условие в интерфейсе и другое на сервере выдачи, называя оба общей политикой. Сохранённая версия политики позволяет сопоставить решение с действовавшим договором.

Время 1 001 относительно now 1 000 является недопустимым будущим значением в этой модели. Мы не исправляем его автоматически до now, потому что тогда использовали бы новое поле, не полученное от источника. Причина отказа сохраняется отдельно от устаревшего ответа.

Как выбирается maxAge

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

Ни одно значение не выбирается только по круглому числу из старого примера. Досье содержит источник параметров, дату, назначение и версию политики. Дополнительные ограничения для L2, включая состояние sequencer, также анализируются отдельно следующей главой.

Важно не выдавать maxAge за гарантию, что ответ всегда обновится вовремя. Это наше правило принятия, которое может привести к отказу при действительной задержке. Операционная модель должна уметь объяснить такое состояние и наблюдать его без скрытого отключения проверки.

Сохранённый счёт при старом feed

Курс уже имеет зафиксированную требуемую сумму. Feed затем устарел. Это может остановить создание новых ценовых предложений, но не обязательно отменяет оплату прежнего счёта по ранее выбранной политике. Для исходного фиксированного примера 30 000 сатоши котировка вообще не является обязательным входом платежной сверки.

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

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

Недоступность и резервный источник

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

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

Проверка возраста также не заменяет анализ допустимого диапазона значения. Свежий ответ с положительным, но содержательно неожиданным числом может нарушить прикладные предположения. Если библиотеке нужны дополнительные пределы, они задаются отдельно с ясным основанием и реакцией. Нельзя принять красивую текущую дату за подтверждение любого качества данных. Аналогично старое допустимое по диапазону число не становится свежим. В досье эти условия независимы: происхождение, семантика пары, временная допустимость и дополнительные ограничения. Для каждого нового предложения сохраняют, какая версия набора правил позволила его создать.

Результат временной проверки

Подготовим ожидаемые случаи: допустимый свежий ответ, граничный возраст, просроченный, будущий, нулевой timestamp и ошибка получения. Каждая причина имеет отдельную реакцию; все проверки исходника остаются непроведёнными. Такой набор позволяет позже объяснить результат лаборатории без зависимости от случайного состояния рынка.

Временные поля описаны в Data Feeds API Reference, выбор источника — в Selecting Quality Data Feeds. Теперь библиотека понимает, почему пригодная арифметика требует предварительного временного решения. Следующий урок добавит L2-ограничение: восстановившийся sequencer не означает, что любое ценовое действие уже безопасно выполнять немедленно.

Оглавление серии