Обзор
LaserStream поддерживает сжатую фильтрацию аккаунтов с помощью cuckoo-фильтров. Вместо отправки явного списка публичных ключей в запросе на подписку (32 байта на аккаунт) вы отправляете компактный вероятностный фильтр, который занимает примерно 3–4 байта на аккаунт при передаче. Это позволяет подписаться на сотни тысяч аккаунтов в одном потоке — без сегментирования между подключениями и без чрезмерно больших запросов на подписку. Например, сериализованный фильтр для отслеживания 500 000 аккаунтов занимает около 2,1 МБ, тогда как исходный список публичных ключей — 16 МБ. Это примерно в 7,6 раза меньше. Точная экономия зависит от степени заполнения фильтра: чем ближе он к предельной емкости, тем меньше байтов требуется на один аккаунт.Доступность
Когда использовать cuckoo-фильтры
Типичные сценарии использования: мониторинг всех держателей токена, отслеживание всех позиций в протоколе кредитования или наблюдение за большими наборами кошельков в торговой или аналитической системе.
Принцип работы
- Создайте фильтр на стороне клиента. Добавьте каждый отслеживаемый публичный ключ в
CompressedAccountFilterSet. Начальное значение хеша выбирается случайным образом для каждого фильтра и сериализуется вместе с ним, поэтому сервер хеширует входящие аккаунты с тем же начальным значением, которое использовал ваш клиент. - Прикрепите его к запросу на подписку.
insert_into_subscribe_request()помещает сериализованный фильтр в поток аккаунтов стандартногоSubscribeRequest. - Сервер выполняет вероятностное сопоставление. Поскольку фильтр вероятностный, сервер может отправлять обновления для аккаунтов, которые вы не отслеживаете. Доля ложноположительных результатов составляет менее 1% при полной загрузке. Ложноотрицательных результатов не бывает: каждое обновление отслеживаемого аккаунта будет доставлено.
- Повторно проверяйте каждое обновление локально — этот шаг обязателен. Вызывайте
set.contains(pubkey)для каждого входящего аккаунта перед обработкой. Эта проверка точна, поскольку использует внутреннее множество хешей, поэтому после локальной фильтрации ложноположительных результатов не остается.
Быстрый старт (Rust)
Добавьте SDK в свой проект:Cargo.toml
main.rs
rust/examples/cuckoo_account_filter.rs.
Быстрый старт (JavaScript/TypeScript)
Установите SDK (для поддержки cuckoo-фильтров требуетсяhelius-laserstream версии 0.4.0 или новее):
javascript/examples/cuckoo-account-sub.ts.
Справочник API
CompressedAccountFilterSet объединяет исходный cuckoo-фильтр с точным множеством хешей, поэтому изменения и проверки принадлежности всегда безопасны и точны:
Приведенные выше имена методов соответствуют соглашениям Rust. SDK для JavaScript/TypeScript предоставляет тот же интерфейс с именами в camelCase:
new CompressedAccountFilterSet(capacity) вместо with_capacity, insertIntoSubscribeRequest, isDirty, takeDirty, toProto и так далее. В JavaScript метод insert возвращает логическое значение (true, если элемент добавлен впервые) и выдает исключение TableFullError, когда фильтр переполнен. Публичный ключ можно передать в виде строки base58, исходной последовательности из 32 байтов или любого объекта с методом toBytes().
Всегда используйте CompressedAccountFilterSet, а не обернутый в него исходный CuckooFilter. Метод remove() исходного фильтра может незаметно удалить не тот элемент — это известная и документированная проблема cuckoo-фильтров. Обертка объединяет фильтр с точным множеством хешей, поэтому операции вставки, удаления и проверки наличия всегда выполняются корректно.
Расчет емкости
- Рассчитывайте размер фильтра через
with_capacity(n)на пиковое количество аккаунтов, которое вы планируете отслеживать. - При вставке сверх предельной емкости корректно возвращается
TableFullError— фильтр никогда не повреждается. На практике таблица допускает небольшое превышение емкости, прежде чем начнет отклонять вставки, но не полагайтесь на этот запас. - Размер сериализованных данных определяется емкостью, а не количеством добавленных аккаунтов, поэтому слишком большой фильтр напрасно увеличивает объем передаваемых данных. Выбирайте емкость, близкую к реальному пиковому значению.
Обновление отслеживаемого множества
Когда отслеживаемое множество изменяется — появляются новые аккаунты или удаляются старые:- Вызовите
insert()/remove()дляCompressedAccountFilterSet. - Проверьте
is_dirty()или получите и сбросьте флаг с помощьюtake_dirty(), чтобы определить, изменился ли фильтр с момента последней отправки. - Если фильтр изменен, заново сформируйте запрос с помощью
insert_into_subscribe_request(). В JavaScript его можно повторно отправить в том же потоке с помощьюstream.write(request). В Rust оформите повторную подписку с заново сформированным запросом.
Часто задаваемые вопросы
Can I miss updates for accounts in my filter?
Can I miss updates for accounts in my filter?
Нет. Cuckoo-фильтры дают ложноположительные результаты — дополнительные обновления для неотслеживаемых аккаунтов, — но никогда не дают ложноотрицательных результатов. Каждое обновление отслеживаемого аккаунта будет доставлено.
How many extra (false-positive) updates will I receive?
How many extra (false-positive) updates will I receive?
Менее 1% при полной загрузке и, как правило, еще меньше, если фильтр заполнен не до предельной емкости. Один локальный вызов
contains() для каждого обновления точно отфильтрует такие результаты.Which clients support cuckoo filters?
Which clients support cuckoo filters?
SDK для Rust (
helius-laserstream версии 0.2.0 или новее), SDK для JavaScript/TypeScript (helius-laserstream версии 0.4.0 или новее) и клиент Yellowstone для Rust (yellowstone-grpc-client версии 13.1.0 или новее). SDK для Go пока не поддерживает эту возможность. См. таблицу доступности выше.Can I still use explicit pubkey lists?
Can I still use explicit pubkey lists?
Да. Стандартные фильтры
account: [...] работают без изменений и остаются оптимальным выбором для небольших множеств аккаунтов — примерно до 10 000. См. руководство по подписке на аккаунты.Do compressed filters work with matchMints?
Do compressed filters work with matchMints?
Да. Когда сжатый фильтр прикреплен к подписке на транзакции и установлен
matchMints: true, сервер проверяет по фильтру не только ключи аккаунтов транзакции, но и адреса выпуска токенов из балансов до и после транзакции. См. Фильтрация по адресу выпуска токена.Связанные материалы
Account Subscriptions
Стандартная фильтрация аккаунтов с помощью фильтров по владельцу, размеру данных и memcmp.
Clients & SDKs
SDK для TypeScript, Rust и Go с автоматическим повторным воспроизведением и переподключением.
Token Mint Filtering
Сопоставление транзакций по адресу выпуска токена с помощью
matchMints, в том числе внутри сжатых фильтров.