# Почему «обнаружен» ≠ «оплачен»: реорганизация блокчейна и откат блоков

> Что такое реорганизация блокчейна (реорг), почему обнаруженный платёж ещё не оплачен и что делает CryptoLike при откате блока с платежом: статусы, леджер, вебхуки.

Source: https://cryptolike.net/ru/blog/blockchain-reorg-explained
Published: 2026-10-04 · Updated: 2026-10-04 · Author: CryptoLike team

Главное:

- Реорг — замена последних блоков цепочки другой веткой; перевод, который вы уже видели, может исчезнуть или попасть в другой блок.
- CryptoLike держит обнаруженный перевод на балансе pending и зачисляет его только по достижении порога подтверждений актива; откат до порога не трогает доступный баланс.
- Перевод, откатившийся до порога, возвращает платёж в прежний статус без вебхука по инвойсу; откат подтверждённого перевода сторнируется в леджере, и приходит invoice.reverted или deposit.reverted.
- Отгружайте по paid, останавливайтесь на reverted и обрабатывайте каждый вебхук один раз по event_id. Если перевод снова попадёт в блок, придёт invoice.paid, пока инвойс открыт, или invoice.late_payment, если он уже истёк.

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

## Что такое реорганизация блокчейна?

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

Конкурирующие ветки возникают потому, что блоки создают много независимых участников. В Bitcoin и Litecoin два майнера могут найти блок почти одновременно, и узлы идут за тем, который увидели первым, пока одна из веток не станет длиннее. Ethereum и TRON выпускают блоки по расписанию, но и их последние блоки могут быть заменены, пока сеть не считает их окончательными. В любой сети чем глубже блок, тем меньше шанс, что его заменят. Короткое определение — в глоссарии: [реорганизация блоков](https://cryptolike.net/ru/glossary/reorg).

## Почему «обнаружен» — ещё не «оплачен»?

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

| Стадия | Статус платежа | Что видит плательщик | Вебхук | Ваш баланс |
|---|---|---|---|---|
| Перевод виден в блоке | `pending` | «Платёж обнаружен. Ожидаем подтверждения.» | `invoice.pending` или `deposit.pending` | Вся сумма в `pending`, вывести её нельзя |
| Порог набран | `paid` (или `underpaid`, если суммы не хватает) | «Платёж подтверждён.» | `invoice.paid` или `deposit.confirmed` | Сумма за вычетом комиссии платформы в `available` |
| Подтверждённый перевод откатился | Пересчитан: `paid`, `underpaid`, `pending` или `new` | Страница обновляется сама | `invoice.reverted` или `deposit.reverted` | Зачисление и комиссия сторнированы |

Переводы, которые ещё не попали в блок, CryptoLike не читает, поэтому `pending` уже означает «в блоке». Страница оплаты показывает и `detected_amount` — сумму переводов, которые видны, но не подтверждены; в документации API прямо сказано, что она не зачислена и может исчезнуть при реорганизации. Сколько подтверждений нужно каждому активу и почему числа в сетях разные, разобрано в статье [сколько подтверждений нужно криптоплатежу](https://cryptolike.net/ru/blog/crypto-payment-confirmations); текущие значения — в `GET /v1/currencies` и на [страницах монет](https://cryptolike.net/ru/coins), например [Bitcoin](https://cryptolike.net/ru/coins/bitcoin).

## Как CryptoLike замечает реорг?

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

Дальше шаги всегда одни и те же:

1. Все переводы на ваши адреса в блоках выше общего помечаются как осиротевшие (orphaned), и для леджера публикуется событие об этом.
2. CryptoLike читает новую ветку от общего блока вверх, по одному блоку.
3. Перевод, который снова появился в новой ветке, обнаруживается заново и считает подтверждения от своего нового блока; получатель и сумма берутся из нового блока.
4. Записи, которые выглядят подтверждёнными, перед подсчётом сверяются с сохранённой цепочкой заголовков блоков, поэтому подтверждению из заменённого блока не доверяют.

У автоматической обработки есть предел. CryptoLike хранит окно последних блоков каждой сети: удвоенный самый строгий порог подтверждений среди её активов, но не меньше 8 блоков. Реорганизация глубже этого окна останавливает обработку этой сети, пока её не проверит команда CryptoLike: из ветки, которую нельзя проверить, ничего не зачисляется и не сторнируется. Платежи в этой сети на это время ждут; те, у которых истёк срок оплаты, как обычно закрываются как `expired`.

## Что происходит с платежом, если его блок откатился?

Действия CryptoLike зависят от того, как далеко платёж успел продвинуться. Правило одно для всех четырёх сетей — Bitcoin, Litecoin, Ethereum и TRON; различается только порог подтверждений актива.

| Ситуация | Статус | Леджер | Вебхук |
|---|---|---|---|
| Инвойс, перевод ещё ниже порога | Снова `new` или остаётся `pending`, если на адрес ждёт другой перевод | Сумма списывается из `pending` | Нет; событие записано в истории платежа в кабинете |
| Инвойс в `paid` или `underpaid`, откатился подтверждённый перевод | Пересчитан по тому, что ещё подтверждено: `paid`, `underpaid`, `pending` или `new` | Сторнированы подтверждение, комиссия и зачисление | `invoice.reverted` с новыми `paid_amount` и `remaining_amount` |
| Статический адрес, любая стадия | В разделе «Транзакции» перевод в статусе «Отменена сетью» | Сторнируется всё, что было проведено | `deposit.reverted`; `confirmed_reversed: true`, если сумма уже была доступна |
| Перевод снова попал в новую ветку | Открытый инвойс: `pending`, затем `paid` по достижении порога. Если срок инвойса истечёт раньше, он закрывается как `expired` и так и остаётся | Зачисляется заново | Открытый инвойс — `invoice.paid`, истёкший — `invoice.late_payment`, статический адрес — `deposit.confirmed`; у каждого новый `event_id` |
| Подтверждённая сумма уже выведена | Статус инвойса не меняется до разбора | Автоматического сторно нет; баланс не уходит в минус | Нет; случай разбирает команда CryptoLike |

Две детали. Если откатился только излишек и инвойс остался `paid`, `invoice.reverted` не приходит: то, на что вы опирались, не изменилось. А на закрытом инвойсе — истёкшем или отменённом — откат уже подтверждённого позднего платежа всё равно даёт `invoice.reverted`, хотя статус остаётся прежним.

## Что записывается в леджер?

Леджер никогда не редактирует и не удаляет записи: реорг проводится новыми записями сторно, зеркальными исходным. CryptoLike сторнирует в порядке, обратном зачислению: сначала подтверждение (`available` обратно в `pending`, комиссия платформы возвращается), затем само зачисление (`pending` обратно за пределы платформы).

Так учёт остаётся проверяемым. Каждая проводка сбалансирована, зачисление и его сторно лежат рядом со ссылкой на один и тот же перевод, а счёт по-прежнему сходится: «зачислено − сторно − выплаты − баланс = 0». Если перевод снова попадёт в блок, он зачисляется под следующим поколением того же ключа, поэтому повтор старого события не зачислит его дважды.

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

## Как интеграции обрабатывать реорг?

Считайте каждый вебхук описанием текущего состояния, а не шагом в одну сторону. Если откатившийся перевод снова попадёт в блок, открытый инвойс пройдёт `paid` → `reverted` → `paid`. Но часто срок к этому моменту уже вышел: подтверждения отсчитываются заново от нового блока, а инвойс по умолчанию живёт 30 минут. Тогда инвойс закрывается как `expired`, а вернувшиеся деньги зачисляются и приходят событием `invoice.late_payment`. Код должен справляться с обоими вариантами без ручной помощи.

- **Отгружайте по `paid`, а не по `pending`.** `invoice.pending` — сигнал о ходе оплаты. Если перевод откатится до порога, отдельного вебхука по инвойсу не будет: платёж может просто вернуться в `new` и позже истечь.
- **Обрабатывайте `invoice.reverted`.** Если заказ ещё не отгружен, держите его в ожидании; если отгружен — отправьте на проверку. Плагины для CMS делают именно так: оплаченный заказ после `reverted` переходит в статус проверки. Если затем придёт `invoice.late_payment`, деньги снова на балансе, а статус остаётся `expired`: отгрузите заказ или верните деньги покупателю.
- **Применяйте каждое событие один раз по `event_id`.** Доставка — «хотя бы один раз» и без фиксированного порядка: сохраняйте `event_id`, пропускайте повторы и сравнивайте `created_at`, а не порядок прихода. Как это сделать в коде, показано в статье об [идемпотентности в платёжных API](https://cryptolike.net/ru/blog/idempotency-in-payment-apis).
- **Сначала проверяйте подпись.** Поддельный `invoice.paid` опаснее реорга — см. [как проверить подпись вебхука](https://cryptolike.net/ru/guides/verify-crypto-payment-webhooks).
- **Доверяйте суммам из события, а не своим подсчётам.** Каждое событие инвойса несёт платёж целиком с текущими `paid_amount` и `remaining_amount`. В Ethereum позиция перевода токена внутри блока может измениться, когда транзакция попадёт в блок заново, поэтому собственный ключ из `txid` и `output_index` может не совпасть с новым появлением.
- **Если сомневаетесь — спросите API.** `GET /v1/invoices/{id}` возвращает текущий статус и суммы.

Если вы ещё выбираете провайдера, вопрос о том, как он обрабатывает реорги, вполне уместен — он есть в списке из статьи [как выбрать криптопроцессинг](https://cryptolike.net/ru/blog/choose-crypto-payment-gateway).

## Как встроить обработку реорга в интеграцию

Отдельной настройки для реоргов в CryptoLike нет: статусы и вебхуки, описанные выше, работают для каждого платежа и статического адреса. С вашей стороны нужен обработчик вебхуков.

1. В кабинете откройте «Вебхуки», добавьте эндпоинт и подпишите его на `invoice.paid`, `invoice.reverted`, `invoice.late_payment`, `deposit.confirmed` и `deposit.reverted` или на все события (`*`).
2. Пусть обработчик проверяет подпись, сохраняет `event_id`, а `invoice.paid` переводит заказ в «готов к отгрузке», `invoice.reverted` — в «ожидание».
3. Проверьте сценарий в тестовых сетях с тестовым ключом — шаги есть в руководстве по [тестовым криптоплатежам](https://cryptolike.net/ru/guides/test-crypto-payments), — а список событий держите под рукой в [справочнике по вебхукам](https://cryptolike.net/ru/docs/webhooks).

## Вопросы и ответы

### Что такое реорг в блокчейне?

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

### Может ли оплаченный криптоплатёж откатиться?

Со стороны сети — только если реорг отбросит блок с уже подтверждённым переводом. Тогда CryptoLike сторнирует зачисление в леджере, пересчитывает платёж и отправляет `invoice.reverted` (или `deposit.reverted` для статического адреса). Если перевод снова попадёт в блок, пока инвойс открыт, придёт новый `invoice.paid`; если инвойс за это время истёк, статус останется `expired`, а вместо `paid` придёт `invoice.late_payment`. Остановите выполнение заказа на `reverted` и решайте заново по тому из двух событий, которое придёт.

### Придёт ли вебхук, если ожидающий платёж исчез?

Для инвойса — нет. Перевод, откатившийся до порога, не был зачислен, поэтому платёж тихо возвращается в `new` (или остаётся `pending`, если ждёт другой перевод), а событие записывается в его историю. Для статического адреса `deposit.reverted` приходит на любой стадии.

### Что будет, если деньги из откатившегося платежа уже выведены?

Леджер сам не уводит баланс в минус и не создаёт долг. Перевод помечается как откатившийся, а случай передаётся команде CryptoLike, которая решает его вместе с вами. Для этого нужен реорг глубже порога подтверждений актива, а порог задан так, чтобы такой реорг не был практическим риском.

### Одинаково ли CryptoLike обрабатывает реорг во всех сетях?

Да. В Bitcoin, Litecoin, Ethereum и TRON работают одна и та же проверка блок за блоком, одни и те же статусы, сторно в леджере и вебхуки. Различается порог подтверждений каждого актива, опубликованный в `GET /v1/currencies`, — потому что сети по-разному выпускают блоки и по-разному делают их окончательными.
