Объявление события в Solidity задаёт именованный формат для записи аргументов. Лог — это конкретная запись, созданная механизмом журналирования виртуальной машины Ethereum, EVM. Чтобы понять различие между логами и событиями Ethereum, полезно разделить три вещи: определение формата, появившуюся запись и смысл, который приписывают её байтам.
Это различие особенно заметно в обозревателе блоков: рядом с понятным названием события могут отображаться шестнадцатеричные поля topics и data. Название, декодированные значения и исходная запись отвечают на разные вопросы. Удобное представление помогает читать данные, однако для их интерпретации нужны подходящая схема события и контекст.
1. Объявление события задаёт формат записи
События Solidity предоставляют абстракцию над механизмом журналирования EVM. При вызове события его аргументы записываются в структуру логов транзакции. Объявление описывает возможную запись, но само по себе не подтверждает, что такая запись действительно появилась. Эту связь и необходимые сведения для интерпретации объясняет документация Solidity о контрактах.
Например, в условной программе можно объявить событие Reading с двумя аргументами типа «беззнаковое целое число». Так определяется формат. Чтобы говорить о конкретном срабатывании, потребуется отдельная запись, созданная при исполнении.
Поэтому при чтении исходного кода и истории исполнения стоит задавать разные вопросы. Есть ли в программе объявление нужного события? Есть ли конкретный лог, который предстоит разобрать? Наличие определения не заменяет свидетельство отдельного срабатывания, а найденная запись ещё требует правильной интерпретации.
2. Адрес источника, topics и data читают отдельно
Основу записи составляют три части:
- Источник записи, или emitter: поле
addressуказывает адрес, от которого произошёл лог. - Topics: массив, содержащий от нуля до четырёх элементов длиной 32 байта каждый.
- Data: при кодировании событий по правилам Solidity это последовательность байтов с ABI-кодированными неиндексируемыми аргументами.
Адрес источника отвечает на вопрос о происхождении лога. Одно его присутствие не устанавливает, что перед нами отправитель транзакции или получатель средств. Для присвоения таких ролей нужны отдельные основания.
В документации Ethereum JSON-RPC приведены определения этих полей и пример лога, созданного EVM при исполнении транзакции и включённого в её квитанцию. Пример показывает, где может находиться лог; из него не следует, что любая транзакция обязательно создаёт такую запись. Квитанция содержит сведения о транзакции в целом, а здесь мы разбираем отдельный элемент внутри неё.
Если нужно понять, какое программное обеспечение предоставляет сведения через RPC, пригодится материал об узлах и клиентах Ethereum. При разборе конкретного лога полезно сохранять различие между полученными полями и объяснением их смысла.
3. Содержимое topics зависит от правил события
Для неанонимного события, использующего соглашения Solidity ABI, в topics[0] находится Keccak-хеш имени события и списка канонических типов его параметров. Если событие называется Reading и принимает два параметра uint256, текст его сигнатуры выглядит так: Reading(uint256,uint256). Имена параметров и отметка indexed в эту формулу не входят.
У анонимного события топик с хешем сигнатуры отсутствует. Поэтому первый элемент массива нельзя автоматически считать идентификатором события, пока не установлено, какое правило применяется к записи.
Индексируемый аргумент типа uint256 представлен непосредственно в соответствующем топике как 32-байтовое значение ABI. Переносить это правило на любые типы параметров нельзя. Для индексируемых массивов, включая массивы фиксированной длины, строк, динамического типа bytes и структур используется Keccak-хеш специального кодирования. Динамический bytes и байтовые типы фиксированной длины здесь необходимо различать.
Как объясняет спецификация Solidity ABI, такое представление позволяет искать совпадения с заранее известными значениями, но не даёт приложению декодировать неизвестное исходное значение из одного этого топика. Если исходное значение известно из другого источника, это уже дополнительные сведения, выходящие за пределы самого топика.
4. ABI задаёт контекст декодирования
Для корректного декодирования нужны сведения о типе события: типы аргументов, отметки indexed и признак анонимности. ABI либо равнозначная схема события предоставляет этот контекст. Сам лог не хранит полное описание типа события рядом со значениями.
Это важно и тогда, когда инструмент показывает убедительные названия полей. Переданная схема объясняет инструменту, как трактовать байты. Из различия между записанными данными и внешним описанием типов следует ограниченный вывод: успешное декодирование по выбранной схеме само по себе не подтверждает, что схема соответствует рассматриваемой записи.
Есть и дополнительное ограничение сопоставления сигнатур. Документация Solidity указывает, что анонимное событие может имитировать топик сигнатуры другого события. Следовательно, одного совпадения топика недостаточно для подтверждения предполагаемого объявления. Этот вывод не означает, что тем самым подделан адрес источника: происхождение записи и интерпретация топиков остаются разными вопросами.
5. Гипотетический пример записи Reading
Гипотетический пример: допустим, вымышленный контракт создаёт неанонимное событие, объявленное как event Reading(uint256 indexed sensor, uint256 value);, с аргументами (7, 42). Предположим также, что запись соответствует правилам Solidity ABI для этого объявления. Это учебная ситуация, а не наблюдение реальной транзакции.
Из этих предпосылок и правил кодирования следует такой разбор:
addressуказывает адрес условного контракта, создавшего лог. Конкретный адрес в примере не задан.topics[0]содержит Keccak-хеш строкиReading(uint256,uint256).topics[1]кодирует индексируемый аргументsensorсо значением 7.dataкодирует единственный неиндексируемый аргументvalueсо значением 42.
Размещение последних двух значений — вывод из заданного объявления. Первый топик занят сигнатурой неанонимного события, следующий отведён индексируемому аргументу, а неиндексируемый аргумент попадает в data.
При стандартном ABI-кодировании беззнаковые целые записываются старшими байтами вперёд, то есть в порядке big-endian, и дополняются нулевыми байтами слева до длины 32 байта. Поэтому слово с номером условного датчика заканчивается шестнадцатеричным 07, а слово в data — 2a, что соответствует десятичному числу 42. Предшествующие байты каждого слова равны нулю.
Что подтверждает число 42?
При принятой схеме оно устанавливает декодированное значение аргумента. В условиях примера не заданы ни физическая единица измерения, ни денежная единица, ни операция оплаты. Следовательно, одна эта гипотетическая запись не подтверждает, что состоялся платёж на сумму 42.
Это ограничение не означает, что логи никогда не могут служить свидетельством экономической активности. Для более содержательной интерпретации потребовались бы сведения о поведении соответствующего контракта и контексте исполнения. В данном упражнении декодирование аргумента и подтверждение экономического результата — разные этапы обоснования.
6. Чек-лист для чтения лога
- Отделите определение от срабатывания. Перед вами объявление события или конкретная созданная запись?
- Определите источник. Прочитайте адрес лога как адрес его происхождения, не назначая ему дополнительные роли участников.
- Установите схему. Уточните типы аргументов, позиции индексируемых параметров и признак анонимности.
- Проверьте смысл топиков. Должен ли присутствовать хеш сигнатуры? Содержат ли топики аргументов непосредственные значения или хеши?
- Декодируйте data с явными предпосылками. Сохраняйте различие между исходными байтами и названиями либо значениями, полученными с помощью схемы.
- Ограничьте вывод. Укажите, что установлено записью и контекстом, а какие единицы измерения и результаты остаются неподтверждёнными.
Этот список подходит для учебного разбора документации и примеров записей. Ссылки на первичные источники обосновывают техническое объяснение, но сами по себе не подтверждают безопасность конкретного контракта или экономический результат.
Образовательный материал подготовлен с помощью ИИ. Он объясняет интерпретацию записей и не рекомендует совершать транзакции или подписывать запросы кошелька.