Вход в кабинет

Мониторинг транзакций: подтверждения, реорганизации, повторы

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

Жизненный цикл транзакции

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

Что такое подтверждение

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

Реорганизации: когда блок отменяется

Иногда два майнера или валидатора почти одновременно предлагают блок — и на какое-то время в сети существуют две конкурирующие версии цепочки. Побеждает та, что в итоге набирает больше подтверждений; блоки проигравшей ветки отбрасываются, а транзакции, которые были только в них, возвращаются в мемпул, будто их и не подтверждали. Это называется реорганизацией. Именно от неё защищает ожидание нескольких подтверждений: чем глубже транзакция закопана под другими блоками, тем менее вероятна реорганизация вокруг неё. У разных сетей — от Bitcoin до XRP Ledger — разная скорость появления блоков и разная механика финализации, поэтому и глубина реорганизаций отличается.

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

Повторы: как не засчитать перевод дважды

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

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

Как это выглядит на практике через прокси

Прокси на CryptoSafe Nodes не присылает уведомления сам — он отвечает только на запрос, который отправили вы. Поэтому мониторинг строится на регулярном опросе: сервис периодически запрашивает статус нужной транзакции или последние блоки и сравнивает результат с тем, что видел раньше.

статус транзакции — пример
# ethereum — имя ноды для примера, точное название — в личном кабинете
curl -X POST https://nodes-api.cryptosafe.pro/proxy/ethereum \
  -H "Authorization: <ваш-ключ>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["<хеш-транзакции>"],"id":1}'

# поле blockNumber в ответе появляется только после включения в блок

Для TRON похожий статус возвращает wallet/gettransactioninfobyid на странице TRON API, а для XRP Ledger — метод tx или account_tx, описанный на странице XRP API. Логика одна и та же для любой сети: опрашивать нужный метод, следить за глубиной подтверждений и не считать перевод окончательным раньше времени.

Что важно не забыть

Три практических вывода: ждите подтверждений соразмерно риску, а не фиксированное число «на все случаи»; отслеживайте не только высоту блока, но и то, что блок с транзакцией не исчез при реорганизации; используйте хеш транзакции как ключ идемпотентности, чтобы повторный опрос не привёл к двойному зачислению. Если задача — именно приём платежей в USDT, дополнительные детали разобраны в статье «Как принимать USDT», а если нужно поднять историю за прошлые периоды — в статье об архивных нодах.

Нужен доступ к ноде для отслеживания транзакций?

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

Вход в кабинет