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

Bitcoin-платежи: истечение срока и поздний перевод

Счёт фиксирует адрес, цену и срок, но Bitcoin-адрес не перестаёт принимать средства в момент закрытия страницы. Читатель может сохранить QR и отправить перевод позже. Поэтому истечение срока означает изменение условий обработки заказа, а не исчезновение денежного поступления.

В этом уроке опишем отдельную ветку поздней оплаты для курса 17. Учебный счёт действует до условного времени 12:30 UTC. Мы не запускаем таймер, узел или базу; моменты времени служат входами для разбора политики. Настоящий порядок действий продавца должен быть определён до будущего использования оплаты.

Что именно истекает

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

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

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

Выбираем явную учебную политику

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

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

before expiry + sufficient eligible amount → payment_qualified
expired + no incoming output → expired_unpaid
expired + incoming output → late_payment_review
already qualified → preserve decision history

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

Какое время нам известно

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

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

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

Храним состояние срока отдельно

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

def temporal_position(invoice, position, now, has_output):
    expired = now >= invoice["expires_at"]
    if invoice.get("qualified_at") is not None:
        return "qualified_history"
    if expired and has_output:
        return "late_payment_review"
    if expired:
        return "expired_unpaid"
    if position.remaining_sats == 0:
        return "ready_for_policy_decision"
    return "awaiting_or_partial"

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

Условие now >= expires_at задаёт точную границу. Если договориться о другом включении конечной секунды, это тоже нужно описать явно. Время браузера не участвует: пользователь может изменить часы устройства, но серверный снимок условий и источник решения сохраняются.

Меняем условие: перевод виден перед сроком

В 12:29 наблюдатель увидел 30 000 сатоши без подтверждений, а в 12:31 глубина достигла двух. По выбранной простой политике это поздний момент квалификации и требуется разбор. Другой продавец мог бы заранее разрешить такое ожидание, но у нашей версии этого исключения нет.

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

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

Поздняя частичная оплата

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

Если пользователь создал новый заказ, не переносим старые выходы в его сумму молча. Такой перенос изменяет назначение денег и должен иметь отдельную запись. Иначе один и тот же outpoint начнёт участвовать в двух счетах или потеряет исходную историю.

Срок не скрывает поступление

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

Разбор результата

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

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

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