Receipt в Ethereum: ожидание результата транзакции
Оглавление курса «Web3-интерфейс: реестр в браузере» · Урок 19 из 30.
Хеш транзакции сообщает, какую отправленную операцию нужно наблюдать. Исход исполнения отражается в receipt. В этом уроке дождёмся receipt, различим успех и откат, а затем перечитаем запись курса 17. Результат — интерфейс объявляет публикацию исполненной только после соответствующего сетевого наблюдения.
Используем журнал отправки предыдущего урока и Public Client той же сети. Кошелёк после получения хеша может переключиться на другой аккаунт: наблюдение всё равно относится к сохранённой операции. Код и транзакции не запускались. Указанное число подтверждений является учебной политикой ожидания, а не универсальным правилом финальности всех сетей.
Receipt относится к включённой транзакции
Пока транзакция ожидает, узел может не вернуть receipt. Это не доказательство отката и не повод немедленно отправить новый publish. Receipt появляется после включения и содержит, среди прочего, статус исполнения и данные блока. Успешный статус означает, что EVM не завершила эту транзакцию откатом, но дальнейшая история цепочки всё ещё требует понимания выбранной политики подтверждения.
При откате изменения storage и события вызова не сохраняются как успешный результат операции. Комиссия за фактическое исполнение включённой транзакции при этом имеет собственную семантику и не становится автоматически нулевой. Пользователю важно знать, что ошибка исполнения отличается от отказа подписывать: в одном случае сеть уже обработала действие.
В базовом контракте успешный publish записывает отпечаток и устанавливает активность. Однако позже другой успешный вызов может заменить выпуск. Поэтому receipt первоначальной публикации и текущее состояние карточки отвечают на разные вопросы. История говорит «эта операция была исполнена», getter — «сейчас записано это значение».
Наблюдение через viem
Создадим observe-publication.js. Функция получает сохранённый хеш, проверяет статус и возвращает receipt. Она не делает нового запроса подписи и не зависит от текущего аккаунта кошелька.
import { publicClient } from './client.js';
export async function observePublication(hash) {
const receipt = await publicClient.waitForTransactionReceipt({
hash,
confirmations: 1,
timeout: 120_000,
});
if (receipt.status !== 'success') {
return { status: 'reverted', receipt };
}
return { status: 'included', receipt };
}
Одна подтверждённая позиция здесь выбрана для простого локального наблюдения. В regtest-подобной лаборатории EVM блоки могут создаваться управляемо, а в публичной сети семантика финальности определяется её консенсусом и инфраструктурой. Интерфейс не должен называть первое включение абсолютной необратимостью.
Тайм-аут 120 секунд ограничивает одну попытку ожидания. Он не означает, что транзакция обязательно не попадёт в блок на 121-й секунде. При тайм-ауте журнал сохраняет хеш и неизвестный текущий результат. Пользователь может продолжить наблюдение; повторная подпись не выполняется автоматически.
Сверка ожидаемого эффекта
После успешного receipt читаем новый снимок выбранного реестра. Если он показывает введённый отпечаток и активность, карточка соответствует ожидаемому текущему состоянию. Если показывает другой выпуск, нельзя просто заменить его локальным аргументом операции: позже могла произойти новая публикация или чтение относится к другому блоку.
Для точного исторического эффекта можно читать состояние на блоке receipt и разбирать событие Published соответствующей транзакции. Это устанавливает связь конкретного исполнения и записанных данных. Текущее чтение остаётся отдельным наблюдением. В простом интерфейсе достаточно показать, что операция исполнена, а текущий выпуск уже отличается, с доступной историей изменения.
Если receipt содержит успешный статус, но нужного события нет, следует проверить адрес и ABI операции. Успешная транзакция могла относиться к другому методу или экземпляру. В нашем маршруте запрос был сформирован из проверенного намерения, однако журнал всё равно сохраняет адрес назначения и аргументы для расследования. Один зелёный статус по любому хешу не удостоверяет смысл публикации.
Номер и хеш блока
В журнале сохраняются blockNumber и blockHash. Номер удобен для сортировки, хеш связывает receipt с конкретным наблюдаемым блоком. При реорганизации прежний блок может перестать быть каноническим. Политика подтверждения решает, когда приложение считает наблюдение достаточно устойчивым для своей задачи, но не удаляет саму возможность изменения ветви.
Если receipt повторно найден в другом блоке, история наблюдения обновляется с явным указанием изменения. Не нужно выдавать два включения одного хеша за две самостоятельные публикации. Прикладной идентификатор операции и факты её сетевого положения разделяются в данных журнала.
Для локального упражнения blockHash является ожидаемым динамическим значением. Здесь не приводится выдуманный конкретный хеш и не утверждается, что он был получен запуском. В тексте фиксируем только структуру и смысл поля. Это сохраняет честную границу между подготовленным исходником и фактическим отчётом лаборатории.
Ошибка после успеха
Повторное чтение карточки может завершиться сетевым отказом после успешного receipt. В этом случае операция остаётся включённой, а обновление карточки — не завершённым. Интерфейс сообщает обе характеристики отдельно: «публикация исполнена; не удалось обновить текущие сведения». Нельзя задним числом превратить сетевую ошибку чтения в откат транзакции.
Аналогично ошибка DOM-рендеринга не изменяет состояние сети. Если страница перезагрузилась, журнал восстановит хеш и receipt. Поэтому результаты сетевого наблюдения сохраняются независимо от того, успела ли карточка красиво отобразиться. Веб-интерфейс отражает состояние, а не управляет уже исполненным результатом своим наличием.
Для упражнения сравните успешный receipt с последующей новой публикацией, откат и истёкшее ожидание без receipt. Запишите разные статусы операции и карточки. Ожидаемый итог — вы умеете различать отправку, включение, результат и текущее состояние. API ожидания описан в waitForTransactionReceipt.
Статус наблюдения и решение приложения
Журнал может хранить первичный факт успешного receipt и отдельное поле достаточности подтверждения для интерфейса. Тогда изменение политики не переписывает прошлые факты. Для локального упражнения достаточно одного включения, но при переносе на другую сеть решение задаётся заново по её модели финальности. Это явный этап конфигурации, а не автоматическое следствие API.
Если пользователь открыл страницу операции через неделю, текущее чтение курса может показывать совершенно другой выпуск. История объясняет, что прежняя публикация была исполнена в своём блоке. Карточка не должна возвращать старый отпечаток только ради согласования с зелёным статусом операции. Два наблюдения относятся к разным моментам и могут оба быть корректными.