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

Время блока в Solidity: сроки действия записи

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

Новый пример назовём TimedNotice. Он показывает объявление с окончанием срока и использует время блока. Это самостоятельная учебная модель, которую нельзя подставить вместо базового реестра без изменения интерфейса и требований.

Источник времени

В Solidity доступен block.timestamp — временная отметка текущего блока по правилам сети. Она не является локальным временем компьютера читателя или таймером вкладки. Контракт также не просыпается каждую секунду, чтобы автоматически выполнить функцию после срока.

Если getter проверяет block.timestamp < expiresAt, ответ меняется при чтении на новом состоянии времени. Но для выполнения отдельного действия нужна транзакция. Например, отправить сообщение редактору или перенести средства автоматически только из-за сравнения времени контракт не сможет: кто-то должен инициировать предусмотренный вызов.

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

Минимальное объявление со сроком

// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

contract TimedNotice {
    error InvalidExpiry();
    uint256 public immutable expiresAt;

    constructor(uint256 expiresAt_) {
        if (expiresAt_ <= block.timestamp) revert InvalidExpiry();
        expiresAt = expiresAt_;
    }

    function usable() external view returns (bool) {
        return block.timestamp < expiresAt;
    }
}

Перед нами полный отдельный контракт. Он не хранит курс и не объявляет издателя. Конструктор требует будущий срок, getter сообщает, не достигнута ли граница. При точном равенстве block.timestamp == expiresAt ответ false, поскольку выбрано строгое сравнение.

Выбор строгой границы является частью договора. Если заменить < на <=, появится другое поведение в момент равенства. Для часов пользователя это может казаться незначительным, но для проверок и согласованного интерфейса нужно одно точное правило.

Единицы и расчёт срока

Временная отметка выражается в секундах в принятой модели. Нельзя случайно передать миллисекунды JavaScript, полученные обычным Date.now(), и ожидать короткий срок. Значение получится существенно больше. Клиент должен намеренно преобразовать единицы, а контракт — проверять разумные границы, если требования их предусматривают.

Solidity поддерживает удобные суффиксы единиц времени для арифметики. Они помогают выразить длительность, но не являются календарём редакции. Месяц имеет разную длину, часовой пояс страницы может отличаться от UTC, а договор «до конца рабочего дня» требует отдельного определения.

Начало учебного периода: T
Длительность: 3600 секунд
Срок: T + 3600
Ответ до срока: usable=true
Ответ в срок и после: usable=false

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

Точность и манипулирование порядком

Время блока не стоит использовать как источник безопасной случайности. Участники формирования блоков и правила сети влияют на доступные условия. Также граница срока находится рядом с порядком включения транзакций: отправленное до конца действие может исполниться после срока и быть отклонено.

Поэтому интерфейс не должен обещать «нажали за секунду до конца — обязательно успели». Он может заранее предупреждать о приближении границы, но результат определяется состоянием исполнения. Для критических коротких окон нужно изучать правила выбранной сети и проектировать достаточный запас по требованиям.

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

От срока к модели курса

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

Например, издатель может вручную отключить курс раньше срока. Тогда итоговое условие выглядит как сочетание ручной активности и временной границы. В интерфейсе полезно показывать причину: «отключён редакцией» отличается от «срок закончился». Для этого модель должна сохранять достаточно сведений.

Вариант Изменение состояния после срока Результат getter
Базовый CourseCatalog Само не происходит Сохранённый active
TimedNotice Не требуется Сравнение текущего времени
Отдельное действие после срока Нужен вызов Зависит от исполненной операции

Мы сохранили исходный реестр и получили отдельный пример временного условия. Теперь можно объяснить автоматическое вычисление getter без выдуманного фонового исполнения. Глобальные значения и единицы времени дают синтаксис и предупреждения для дальнейшей работы.

Три момента одного действия

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

Интерфейс способен показать приближающуюся границу и предложить обновить данные перед подписью. Но он не управляет временем включения в публичную сеть. Для процесса, где отказ после срока неудобен, бизнес-правило нужно проектировать с учётом таких задержек. Техническая проверка не исправляет неопределённое требование «успеть вовремя».

Историческое чтение usable также относится к выбранному блоку. Срок мог ещё не закончиться на B, а на новом блоке ответ уже false. Оба ответа корректны для своих входных условий. Отчёт должен сохранять момент состояния, чтобы человек не увидел противоречие между двумя наблюдениями.

Теперь изменим локальные часы устройства на час вперёд. Таймер страницы ускорится или покажет истечение, но состояние контракта не получит новый block.timestamp от этого действия. Такой мысленный опыт помогает отделить отображение от окончательного условия.

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

Оглавление курса. Листинги, расчёты и наблюдения здесь разобраны как ожидаемое поведение; компиляция, учебные программы и проверки при написании не запускались.

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