У транзакции создания контракта в Ethereum нет обычного адреса назначения. Она содержит скомпилированный код контракта, а успешно развёрнутый контракт получает собственный адрес. Эти утверждения относятся к разным сторонам создания: к тому, что задано в транзакции, и к результату развёртывания.
Чтобы разобраться в записи о создании, полезно разделить три вещи: поле получателя в транзакции, код этапа инициализации и поле contractAddress в квитанции. Ниже их связь показана на гипотетическом примере. Это объяснение для чтения записей, без процедуры развёртывания.
Почему у транзакции создания нет обычного получателя
В объекте транзакции, описанном в документации Ethereum JSON-RPC, поле to обычно указывает получателя. Для транзакции создания контракта это поле имеет значение null. В данном контексте null означает отсутствие обычного адреса получателя в этом поле. Само значение null адресом не является.
В документации Ethereum о развёртывании создание описано через транзакцию, которая содержит скомпилированный код контракта и не указывает получателя. Это помогает понять отсутствие назначения: речь идёт о создании контракта, а не об обращении к уже существующему получателю.
Важно различать сам принцип и его представление в данных. В объяснении процесса может быть сказано, что получатель не указан. Возвращаемый объект JSON-RPC представляет назначение такой транзакции как to: null. Читать это значение следует в соответствии с назначением поля. Мысленно подставлять туда адрес, появившийся после успешного создания, не нужно.
Поэтому при разборе записи сначала определите, что именно перед вами: сведения о направлении транзакции или сведения о результате её выполнения. Это разные вопросы. Отсутствие обычного получателя и наличие адреса созданного контракта могут согласовываться друг с другом.
Init code и развёрнутый код относятся к разным этапам
В этом концептуальном объяснении термин init code обозначает код, относящийся к этапу создания. Развёрнутый код — это итоговый код контракта, сохранённый после создания. Такое употребление терминов представляет собой поясняющий вывод из документированного процесса, а не полную спецификацию содержимого транзакции создания.
Основания для этого различия приведены в документации Solidity о контрактах. Конструктор выполняется один раз при создании контракта. В нём можно выполнять код инициализации. После выполнения конструктора итоговый код контракта сохраняется в блокчейне. При этом развёрнутый код не включает код конструктора и внутренние функции, вызываемые только из конструктора.
Из этих положений следует полезное для чтения записей различие между кодом, используемым при создании, и кодом, который остаётся после развёртывания. Однако они не дают оснований считать, что весь init code состоит только из конструктора. Они также не позволяют предполагать, что скомпилированное содержимое транзакции представляет собой неизменённую копию итогового развёрнутого кода.
Представьте гипотетическое учебное упражнение с двумя папками: «Код этапа создания» и «Итоговый развёрнутый код». Эти названия помогают упорядочить объяснение. Они не показывают отдельные инструкции, полную структуру содержимого транзакции или побайтовое соотношение конкретных результатов компиляции. На этом уровне важно различать назначение двух этапов.
Такое разграничение полезно и при чтении описаний конструктора. Утверждение о том, что он участвует в инициализации, относится к его роли при создании. Оно само по себе не описывает весь код создания и не подтверждает успешное развёртывание произвольной отправленной транзакции.
Где указан адрес созданного контракта
После развёртывания контракт имеет адрес Ethereum. В документированной квитанции транзакции поле contractAddress сообщает адрес контракта, созданного транзакцией создания; в остальных случаях это поле имеет значение null. Следовательно, поле назначения транзакции и поле адреса созданного контракта нужно читать по отдельности.
Поле hash в объекте транзакции идентифицирует транзакцию. Сам факт наличия её идентификатора не устанавливает успешность создания и не сообщает адрес получившегося контракта. Рассматриваемое здесь поле с адресом результата находится в квитанции.
Имеет значение и статус выполнения. Для квитанций с полем status документация определяет значение 1 как успех, а 0 — как неудачу. Отдельно в ней описаны исторические квитанции до Byzantium, использующие поле root. Объяснение статуса в этой статье относится к квитанциям, содержащим status.
Для ожидающей выполнения транзакции квитанция недоступна. Поэтому нельзя предполагать, что приведённая ниже запись о завершённом создании уже существует, пока транзакция остаётся в состоянии ожидания. При этом одно лишь отсутствие квитанции не даёт полного объяснения обстоятельств транзакции. Определения этих полей приведены в документации Ethereum JSON-RPC.
Описание contractAddress следует рассматривать вместе со статусом выполнения. Само определение поля не устанавливает успешность развёртывания конкретной транзакции и не описывает все варианты значений полей после неудачной попытки создания.
Гипотетическая запись о создании: как её прочитать
Допустим, в вымышленном учебном примере есть транзакция создания и соответствующая ей квитанция. По условию создание завершилось успешно. Обозначим транзакцию как «Транзакция T», а созданный адрес — как «Адрес C». Это условные обозначения, а не настоящие хеш и адрес. Никакого вычисления адреса пример не предполагает.
- Идентификатор транзакции: Транзакция T.
- Назначение транзакции:
to: null. - Входные данные транзакции: скомпилированный код этапа создания, заданный условием упражнения.
- Статус соответствующей квитанции: 1, то есть успех.
- Поле contractAddress соответствующей квитанции: Адрес C.
Обоснованный вывод здесь состоит в том, что null в поле назначения согласуется с наличием адреса созданного контракта в квитанции. Основания вывода — заданное условием успешное создание и документированные значения полей to, status и contractAddress. Поле назначения описывает получателя транзакции, а Адрес C — результат создания, указанный в соответствующей квитанции.
Иными словами, пример не требует переносить Адрес C в поле to, чтобы объяснить запись. У каждого поля своя роль. Согласованность этих значений следует из условий примера и определений полей, а не из расчёта адреса или анализа реальной транзакции.
Вывод ограничен заданными условиями. Он не устанавливает, что произвольная отправленная транзакция завершилась успешно, и не определяет значения всех полей квитанции после неудачного создания. В примере также нет фактического кода, по которому можно было бы анализировать поведение гипотетического контракта.
Чек-лист для чтения записи о создании
При изучении предоставленной записи последовательно ответьте на следующие вопросы. Они помогают собрать основания именно для рассматриваемой интерпретации:
- Какое поле вы читаете? Различайте
toв транзакции иcontractAddressв квитанции. Не приписывайте одному полю назначение другого. - Что указано в назначении? В документированном объекте транзакции создания ожидается null вместо обычного адреса получателя.
- О каком этапе кода идёт речь? Разделяйте инициализацию и итоговый развёрнутый код, особенно когда в объяснении упоминается конструктор.
- Доступна ли квитанция? У ожидающих выполнения транзакций доступной квитанции нет. Само её отсутствие ещё не даёт полного объяснения ситуации.
- Какой результат подтверждают сведения? Если присутствует
status, рассматривайте его значение успеха или неудачи вместе с полем адреса созданного контракта. - Какие допущения сохраняются? Явно отмечайте условные обозначения, заданную успешность и отсутствующие подробности. Не переносите условия учебного примера на произвольную запись.
Этот порядок чтения сохраняет связь между транзакцией создания, этапом инициализации и получившимся адресом, не подменяя анализ отдельных полей предположением об успешном результате.
Материал подготовлен с помощью ИИ в образовательных целях. Вымышленная запись служит упражнением по чтению данных.
Материал по смежной теме: Верификация исходников контракта Ethereum: что подтверждает проверка.