Skip to main content
Мемпул — это то, что стоит между подписанной транзакцией и зафиксированным блоком. Он решает, что стоит держать, в каком порядке транзакции одного отправителя становятся годными к включению, какие пиры узнают о транзакции и что отбрасывается, когда спрос превышает ёмкость. Для торговой сети это несущая конструкция, а не побочная деталь. Поток ордеров и отмен идёт всплесками, концентрируется у отдельных отправителей и чувствителен к задержке асимметрично: опоздавшая отмена хуже опоздавшего ордера. Описанные ниже структуры существуют потому, что одна очередь FIFO ни с чем из этого толком не справляется.

Путь внутрь

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

Как хранятся транзакции

Принятые транзакции не лежат одной плоской очередью. Хранилище поддерживает несколько представлений над одним и тем же набором, и каждое отвечает на свой вопрос.
Один набор принятых транзакцийпять представлений, а не пять очередей
Порядок по счетамКакая транзакция у этого отправителя следующая?
Индекс приоритетаЧто из всех отправителей предложить консенсусу первым?
Индекс сроковУ чего истёк срок?
Индекс таймлайнаО чём этот пир ещё не слышал?
ОтстойникЧто оформлено верно, но пока не годно?
Именно на отстойнике видны ошибки интеграции: валидная транзакция, которая пока не следующая у своего отправителя, отправляется в отстойник, а не отклоняется, — и становится годной, как только закроется дыра перед ней.
Отстойник заслуживает наибольшего внимания, потому что именно на нём становится виден целый класс ошибок интеграции. Транзакция может быть совершенно валидной и всё же не быть следующей в очереди своего отправителя — чаще всего потому, что более ранняя транзакция с того же счёта не пришла или не зафиксирована. Такую транзакцию отправляют в отстойник, а не отклоняют: она остаётся доступной и становится годной к включению в тот момент, когда закроется дыра перед ней. Поэтому клиент, отправляющий не по порядку, получает задержку, а не отказ; но клиент, который так и не закроет дыру, оставит транзакции в отстойнике, пока у них не истечёт срок. Индекс таймлайна делает распространение по пирам инкрементальным. По каждому пиру отслеживается, до какой точки таймлайна он обслужен, поэтому рассылка отправляет то, чего этому пиру не хватает, а не пересылает пул заново. Таймлайн разбит на корзины, а не выстроен в одну линию, и это не даёт одному тяжёлому отправителю занять все слоты рассылки.

Распространение и справедливость

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

Передача в консенсус

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

Что это значит для клиента

  • Отклонение при отправке информативно. Оно произошло до того, как транзакцию сохранили, и его причина описывает то, что клиент может исправить.
  • Молчание — не отклонение. Транзакция может стоять в отстойнике за дырой, которую клиент создал сам. Отслеживайте, что отправлено и что зафиксировано, а не считайте, что отсутствие подтверждения означает потерю.
  • Порядок внутри счёта важен, порядок между счетами — нет. У двух транзакций от одного отправителя есть заданная последовательность. Две транзакции от разных отправителей упорядочивает консенсус, а не то, кто отправил первым.
  • У отмен нет привилегий в мемпуле. Приоритет отмены — свойство исполнения ядра, где отмены идут раньше агрессивных выставлений в том же блоке, а не свойство очереди.