Автор: Павел Найданов 🕵️♂️
Прежде чем разобрать индексирование аргументов в событиях определим что такое Events в Solidity. Перед чтением этой статьи рекомендуем ознакомиться с устройством работы EVM от Luit Hollander "The Ethereum Virtual Machine — How does it work?".
event Transfer(address from, address to, uint256 amount);
События в Solidity являются своего рода абстракцией над системой логирования в EVM. Приложения могут подписываться и слушать события через RPC-интерфейс клиента Ethereum. Вызов события сохраняет параметры события в специальный журнал транзакций.
События этого журнала связаны с адресом контракта, включены в цепочку блоков и остаются там до тех пор пока блок доступен(на данный момент навсегда, но это может измениться с Serenity, так как там будет реализован sharding, proof-of-stake, and moving EVM to eWASM)
Для чего нужны Events?
- Для тестирования. В тестах можно получать события со смарт-контрактов из данных транзакции и проверять их.
- Для восстановления состояния хранилища. Все события хранятся в журнале EVM и могут быть прочитаны.
- Прослушивание событий. Необходимо для оперативного реагирования на изменения во внешнем интерфейсе.
- Создание сабграфов для конвертации и более быстрого чтения данных.
Возможны и другие области применения событий.
Мы определили, что события в Solidity используют инструмент логирования EVM. Для логирования событий в журнал EVM предоставляет 5 opcodes.
LOG0, LOG1, LOG2, LOG3, LOG4
При помощи этих opcodes можно создать запись в журнал. Такая запись состоит из двух частей:
- topic
- data
Topic - это 32-байтные слова, которые используются для описания того, что происходит в событии. Например, трансфер от одного адреса к другому.
Data - это закодированные данные. Например, количество токенов переданных при трансфере.
Различные коды операций (LOG0 … LOG4) необходимы для описания количества тем, которые необходимо включить в запись журнала. Например, LOG1 включает один topic , а LOG4 включает четыре topics. Таким образом, максимальное количество topics, которые могут быть включены в одну запись журнала, равно четырем.
Первый topic всегда является signature события с типами. Другими словами он представлен, как hash keccak(Transfer(address,address,uint256))
. Таким образом для своих событий можно добавить 3 параметра в topics.
Важно! В Solidity существуют анонимные события. Для этого используется ключевое слово anonymous
. Подробнее тут. Для таких событий не используется topic по умолчанию с сигнатурой события. Это значит, что можно добавить 4 собственных topics.
В Solidity для того, чтобы указать, какой параметр необходимо добавить в topic используется ключевое слово indexed
перед названием параметра. Например,
Transfer(address indexed from, address indexed to, uint256 value)
Другими словами параметры событий бывают двух типов:
- indexed
- non-indexed
Параметры с атрибутом indexed
будут записаны в topic записи журнала EVM. Все остальные параметры автоматически будут non-indexed
. Это будет означать, что параметр будет добавлен в специальную структуру данных(data) записи журнала EVM.
Topic и data или indexed и non-indexed лучше всего работают вместе. У каждого есть свои плюсы и минусы. Например, topic доступны для поиска, data — нет. Но включение data намного дешевле, чем включение topic. Кроме того, topic ограничены 4 topic по 32 байта, data не ограничены. Это означает, что data могут включать большие или сложные данные, массивы или структуры.
Подробнее, как работает логирование событий в Ethereum blockchain можно почитать тут.
Каждый indexed
параметр создает topic. Этот параметр исключается из данных и не кодируется. По этому параметру можно обеспечить эффективный поиск.
При помощи запросов JSON-RPC к полными nodes, таким как geth или parity, или сервисам, таким как Infura можно запросить данные событий из блокчейн. Делается это на основе фильтра Блума, который придуман для быстрой проверки принадлежности элемента к множеству.
Для Solidity разработчика важно понимать, как indexed
параметры будут использоваться для фильтров за пределами контрактов. Поэтому предлагаем ознакомиться с документацией ethers js, которая позволяет получать данные из отфильтрованных событий.
Под цифровой 1 мы видим раздел Topics в котором хранятся indexed
параметры. Нулевой параметр - это хеш signature события Transfer(address,address,uint256)
.
Под цифрой 2 мы видим раздел Data в котором хранится non-indexed
параметр uint256 value
.
Под цифрой 3 мы видим переключение типа отображения раздела Data. Помним, что Data хранится в зашифрованном виде.
Простое объяснение использование Solidity Events можно посмотреть в статье от ChainLink.
Пример, где можно посмотреть как работают indexed
и non-indexed
параметры можно в примере из этой же статьи. Ссылка на репозиторий. В репозитории есть пример простого скрипта, который выводит события в консоль.