Перейти к основному контенту
Change page

Транзакции

Транзакции — это криптографически подписанные инструкции от аккаунтов. Аккаунт инициирует транзакцию для обновления состояния сети Эфириум. Самая простая транзакция — это перевод ETH с одного аккаунта на другой.

Предварительные требования

Чтобы лучше понять эту страницу, мы рекомендуем сначала прочитать про аккаунты и наше введение в Эфириум.

Что такое транзакция?

Транзакция Эфириума — это действие, инициированное внешне принадлежащим аккаунтом (externally-owned account, EOA), то есть аккаунтом, управляемым человеком, а не контрактом. Например, если Боб отправляет Алисе 1 ETH, счет Боба должен быть списан, а счет Алисы — пополнен. Это действие, изменяющее состояние, происходит в рамках транзакции.

Diagram showing a transaction cause state change Схема адаптирована из Ethereum EVM illustrated (opens in a new tab)

Транзакции, которые изменяют состояние EVM, должны транслироваться всей сети. Любой узел может транслировать запрос на выполнение транзакции в EVM; после этого валидатор выполнит транзакцию и распространит полученное изменение состояния на остальную часть сети.

Транзакции требуют комиссии и должны быть включены в проверенный блок. Чтобы упростить этот обзор, мы рассмотрим комиссии за газ и валидацию в другом месте.

Отправленная транзакция включает следующую информацию:

  • from — адрес отправителя, который будет подписывать транзакцию. Это будет внешне принадлежащий аккаунт, так как контрактные аккаунты не могут отправлять транзакции
  • to — адрес получателя (если это внешне принадлежащий аккаунт, транзакция переведет средства. Если это контрактный аккаунт, транзакция выполнит код контракта)
  • signature — идентификатор отправителя. Он генерируется, когда приватный ключ отправителя подписывает транзакцию и подтверждает, что отправитель авторизовал эту транзакцию
  • nonce — последовательно увеличивающийся счетчик, который указывает номер транзакции с аккаунта (нонс)
  • value — сумма ETH для перевода от отправителя к получателю (выраженная в Wei, где 1 ETH равен 1e+18 Wei)
  • input data — необязательное поле для включения произвольных данных
  • gasLimit — максимальное количество единиц газа, которое может быть потреблено транзакцией (лимит газа). EVM определяет единицы газа, необходимые для каждого вычислительного шага
  • maxPriorityFeePerGas — максимальная цена потребленного газа, которая будет включена в качестве чаевых валидатору
  • maxFeePerGas — максимальная комиссия за единицу газа, которую готовы заплатить за транзакцию (включая baseFeePerGas и maxPriorityFeePerGas)

Газ — это ссылка на вычисления, необходимые для обработки транзакции валидатором. Пользователи должны платить комиссию за эти вычисления. gasLimit и maxPriorityFeePerGas определяют максимальную комиссию за транзакцию, выплачиваемую валидатору. Подробнее о газе.

Объект транзакции будет выглядеть примерно так:

Но объект транзакции должен быть подписан с использованием приватного ключа отправителя. Это доказывает, что транзакция могла исходить только от отправителя и не была отправлена мошенническим путем.

Клиент Эфириума, такой как Go Ethereum (Geth), будет обрабатывать этот процесс подписания.

Пример вызова JSON-RPC:

Пример ответа:

  • raw — это подписанная транзакция в закодированной форме Recursive Length Prefix (RLP)
  • tx — это подписанная транзакция в формате JSON

С помощью хеша подписи можно криптографически доказать, что транзакция исходила от отправителя и была отправлена в сеть.

Поле данных

Подавляющее большинство транзакций обращаются к контракту с внешне принадлежащего аккаунта. Большинство контрактов написаны на Solidity и интерпретируют свое поле данных в соответствии с .

Первые четыре байта указывают, какую функцию вызывать, используя хеш имени функции и ее аргументов. Иногда вы можете определить функцию по селектору, используя эту базу данных (opens in a new tab).

Остальная часть данных вызова (calldata) — это аргументы, закодированные в соответствии со спецификациями ABI (opens in a new tab).

Например, давайте посмотрим на эту транзакцию (opens in a new tab). Используйте Click to see More (Нажмите, чтобы увидеть больше), чтобы просмотреть данные вызова.

Селектор функции — 0xa9059cbb. Существует несколько известных функций с этой подписью (opens in a new tab). В данном случае исходный код контракта (opens in a new tab) был загружен на Etherscan, поэтому мы знаем, что это функция transfer(address,uint256).

Остальные данные:

0000000000000000000000004f6742badb049791cd9a37ea913f2bac38d01279
000000000000000000000000000000000000000000000000000000003b0559f4

Согласно спецификациям ABI, целочисленные значения (такие как адреса, которые являются 20-байтовыми целыми числами) отображаются в ABI как 32-байтовые слова, дополненные нулями спереди. Поэтому мы знаем, что адрес to — это 4f6742badb049791cd9a37ea913f2bac38d01279 (opens in a new tab). value равно 0x3b0559f4 = 990206452.

Дескрипторы транзакций

Поскольку поле данных содержит непрозрачные шестнадцатеричные байты, может быть крайне сложно проверить, какое действие на самом деле выполнит транзакция. Эта уязвимость «слепого подписания» устраняется с помощью прозрачного подписания (Clear Signing) (opens in a new tab) за счет использования дескрипторов транзакций (opens in a new tab) (определенных в ERC-7730).

Спецификация ERC-7730 использует дескрипторы транзакций (часто структурированные как файлы JSON) для обогащения данных, содержащихся в ABI и структурированных сообщениях, таких как данные вызова транзакций EVM, сообщения EIP-712 и пользовательские операции (User Operations) EIP-4337. Разработчики используют эти дескрипторы для сопоставления конкретных переменных транзакции непосредственно с шаблонами форматирования, гарантируя, что базовые данные остаются машиночитаемыми для приложений.

На фронтенде кошельки используют этот контекст форматирования для перевода непрозрачного байт-кода в понятную, удобочитаемую информацию. Автоматически преобразуя такие значения, как адреса токенов, в распознаваемые тикеры, или суммы в десятичные дроби, пользователи получают сводку точного намерения транзакции на простом языке (например, «Своп 1000 USDC на как минимум 0.25 обернутого эфира (WETH)») перед тем, как они ее подпишут.

Типы транзакций

В Эфириуме существует несколько различных типов транзакций:

  • Обычные транзакции: транзакция с одного аккаунта на другой.
  • Транзакции развертывания контракта: транзакция без адреса получателя ('to'), где поле данных используется для кода контракта.
  • Выполнение контракта: транзакция, которая взаимодействует с развернутым смарт-контрактом. В этом случае адрес получателя ('to') — это адрес смарт-контракта.

О газе

Как уже упоминалось, выполнение транзакций требует газа. Простые транзакции перевода требуют 21000 единиц газа.

Таким образом, чтобы Боб отправил Алисе 1 ETH при baseFeePerGas в 190 Gwei и maxPriorityFeePerGas в 10 Gwei, Бобу нужно будет заплатить следующую комиссию:

(190 + 10) * 21000 = 4,200,000 gwei
--или--
0.0042 ETH

Со счета Боба будет списано -1.0042 ETH (1 ETH для Алисы + 0.0042 ETH в виде комиссии за газ)

На счет Алисы будет зачислено +1.0 ETH

Базовая комиссия будет сожжена -0.00399 ETH

Валидатор оставляет себе чаевые +0.000210 ETH

Diagram showing how unused gas is refunded Схема адаптирована из Ethereum EVM illustrated (opens in a new tab)

Любой газ, не использованный в транзакции, возвращается на аккаунт пользователя.

Взаимодействие со смарт-контрактами

Газ требуется для любой транзакции, в которой задействован смарт-контракт.

Смарт-контракты также могут содержать функции, известные как функции view (opens in a new tab) или pure (opens in a new tab), которые не изменяют состояние контракта. Таким образом, вызов этих функций с EOA не потребует газа. Базовым вызовом RPC для этого сценария является eth_call.

В отличие от доступа с использованием eth_call, эти функции view или pure также часто вызываются внутренне (то есть из самого контракта или из другого контракта), что требует затрат газа.

Жизненный цикл транзакции

После отправки транзакции происходит следующее:

  1. Криптографически генерируется хеш транзакции: 0x97d99bc7729211111a21b12c933c949d4f31684f1d6954ff477d0477538ff017
  2. Затем транзакция транслируется в сеть и добавляется в пул транзакций, состоящий из всех остальных ожидающих транзакций сети.
  3. Валидатор должен выбрать вашу транзакцию и включить ее в блок, чтобы проверить транзакцию и считать ее «успешной».
  4. Со временем блок, содержащий вашу транзакцию, будет обновлен до статуса «обоснованный» (justified), а затем «финализированный» (finalized). Эти обновления дают гораздо большую уверенность в том, что ваша транзакция была успешной и никогда не будет изменена. Как только блок становится «финализированным», его можно изменить только с помощью атаки на уровне сети, которая будет стоить много миллиардов долларов.

Визуальная демонстрация

Посмотрите, как Остин рассказывает о транзакциях, газе и майнинге.

Transactions — ETH.BUILD

A demonstration of how Ethereum transactions work using the ETH.BUILD educational tool.

Смотреть с расшифровкой 

Типизированный конверт транзакции

Изначально в Эфириуме был один формат для транзакций. Каждая транзакция содержала нонс, цену газа, лимит газа, адрес получателя, значение, данные, v, r и s. Эти поля кодируются с помощью RLP и выглядят примерно так:

RLP([nonce, gasPrice, gasLimit, to, value, data, v, r, s])

Эфириум эволюционировал для поддержки нескольких типов транзакций, чтобы позволить реализовывать новые функции, такие как списки доступа и EIP-1559 (opens in a new tab), не затрагивая устаревшие форматы транзакций.

EIP-2718 (opens in a new tab) — это то, что делает такое поведение возможным. Транзакции интерпретируются как:

TransactionType || TransactionPayload

Где поля определяются как:

  • TransactionType — число от 0 до 0x7f, что в сумме дает 128 возможных типов транзакций.
  • TransactionPayload — произвольный массив байтов, определяемый типом транзакции.

На основе значения TransactionType транзакция может быть классифицирована как:

  1. Транзакции типа 0 (устаревшие): Исходный формат транзакций, используемый с момента запуска Эфириума. Они не включают функции из EIP-1559 (opens in a new tab), такие как динамические вычисления комиссии за газ или списки доступа для смарт-контрактов. Устаревшие транзакции не имеют специального префикса, указывающего их тип в сериализованной форме, и начинаются с байта 0xf8 при использовании кодировки Recursive Length Prefix (RLP). Значение TransactionType для этих транзакций равно 0x0.

  2. Транзакции типа 1: Представленные в EIP-2930 (opens in a new tab) как часть обновления Берлин (Berlin) в Эфириуме, эти транзакции включают параметр accessList. Этот список указывает адреса и ключи хранилища, к которым транзакция ожидает получить доступ, помогая потенциально снизить затраты газа для сложных транзакций с участием смарт-контрактов. Изменения рынка комиссий EIP-1559 не включены в транзакции типа 1. Транзакции типа 1 также включают параметр yParity, который может быть либо 0x0, либо 0x1, указывая на четность значения y подписи secp256k1. Они идентифицируются тем, что начинаются с байта 0x01, а их значение TransactionType равно 0x1.

  3. Транзакции типа 2, обычно называемые транзакциями EIP-1559, — это транзакции, представленные в EIP-1559 (opens in a new tab) в рамках обновления Лондон (London) в Эфириуме. Они стали стандартным типом транзакций в сети Эфириум. Эти транзакции вводят новый механизм рынка комиссий, который улучшает предсказуемость за счет разделения комиссии за транзакцию на базовую комиссию и приоритетную комиссию. Они начинаются с байта 0x02 и включают такие поля, как maxPriorityFeePerGas и maxFeePerGas. Транзакции типа 2 теперь используются по умолчанию из-за их гибкости и эффективности, и особенно предпочтительны в периоды высокой перегрузки сети за их способность помогать пользователям более предсказуемо управлять комиссиями за транзакции. Значение TransactionType для этих транзакций равно 0x2.

  4. Транзакции типа 3 (блоб-транзакции) были представлены в EIP-4844 (opens in a new tab) как часть обновления Dencun в Эфириуме. Эти транзакции предназначены для более эффективной обработки данных «блобов» (Binary Large Objects), что особенно выгодно для роллапов уровня 2 (l2), поскольку предоставляет способ публикации данных в сети Эфириум с меньшими затратами. Блоб-транзакции включают дополнительные поля, такие как blobVersionedHashes, maxFeePerBlobGas и blobGasPrice. Они начинаются с байта 0x03, а их значение TransactionType равно 0x3. Блоб-транзакции представляют собой значительное улучшение доступности данных (DA) и возможностей масштабирования Эфириума.

  5. Транзакции типа 4 были представлены в EIP-7702 (opens in a new tab) как часть обновления Пектра (Pectra) в Эфириуме. Эти транзакции разработаны с учетом прямой совместимости с абстракцией учетной записи. Они позволяют EOA временно вести себя как контрактные аккаунты без ущерба для их исходной функциональности. Они включают параметр authorization_list, который указывает смарт-контракт, которому EOA делегирует свои полномочия. После транзакции поле кода EOA будет содержать адрес делегированного смарт-контракта.

Дополнительная литература

Знаете ресурс сообщества, который помог вам? Отредактируйте эту страницу и добавьте его!