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

В BlockVigil мы работаем над внедрением уровня управления транзакциями, ориентированного на платформу Ethereum, что, естественно, требует четкого понимания различных этапов жизненного цикла транзакции Ethereum. Эта статья, первая из серии «BlockVigil Transaction Manager», направлена ​​на то, чтобы дать такое понимание, а также более подробно рассмотреть, как транзакции, выполняющие бизнес-логику, могут давать сбой или в других любопытных случаях «застревать».

Транзакции Ethereum во вселенной DApp

В Ethereum транзакции играют более важную роль, чем просто перевод средств между счетами. Транзакции также могут выполнять методы, определенные в «умном контракте» - фрагменте кода, реализующем бизнес-логику DApp. Очевидно, вам также потребуются транзакции для развертывания смарт-контрактов.

Развертывание смарт-контракта в сети Ethereum

Сеть Ethereum - это децентрализованная одноранговая сеть, в которой ведется запись транзакций между учетными записями. В Ethereum есть два типа учетных записей:

  1. Внешние аккаунты
  2. Контрактные счета

Внешние учетные записи (EOA) - это обычные учетные записи пользователей, идентифицируемые по адресам. Состояние блокчейна можно изменить только с помощью действительной транзакции, асимметрично подписанной закрытым ключом EOA.

Контрактные аккаунты, с другой стороны, появляются, когда новый смарт-контракт «развертывается» в блокчейне Ethereum. Эти развертывания по контракту инициируются EOA посредством подписанных транзакций.

Транзакция, развертывающая смарт-контракт в сети Ethereum, характеризуется двумя следующими особенностями:

  1. Эта транзакция не адресована существующему EOA. С другой стороны, при выполнении этой транзакции будет создана новая учетная запись контракта, идентифицируемая по адресу.
  2. Поле data транзакции содержит закодированные данные байт-кода развертываемого смарт-контракта. Этот байт-код находится на виртуальной машине Ethereum (EVM) и позволяет выполнять вызовы методов в развернутом смарт-контракте.

Вызовы выполнения методов для развернутых смарт-контрактов

После успешного развертывания смарт-контракта в сети Ethereum методы могут быть выполнены в развернутом смарт-контракте.

Естественно, транзакции, которые пытаются выполнить методы контракта, должны:

  1. быть адресовано контрактной учетной записи, где развернут смарт-контракт.
  2. содержат закодированную информацию о том, какой метод выполнить, и соответствующие аргументы.

Отправка транзакции → проверка → подтверждение

Итак, в зависимости от того, хотите ли вы развернуть смарт-контракт или выполнить метод в развернутом контракте, вы создаете транзакцию. Но эта транзакция должна быть выполнена, и изменение состояния должно быть записано в блокчейне Ethereum.

Для этого транзакция после создания должна пройти несколько этапов:

  1. Отправка транзакции на узел Ethereum, на котором запущен клиент, такой как geth / parity.
  2. Проверка транзакции и трансляция узлом Ethereum
  3. Подтверждение транзакции майнер-нодой

Отправка транзакции на узел Ethereum и проверка

Как только сложная часть создания транзакции завершена, транзакция сначала отправляется на узел Ethereum. Узел Ethereum - это любая вещь, которая запускает клиент Ethereum, например Geth / Parity, и пытается синхронизироваться с состоянием блокчейна.

Проверка транзакции на узле Ethereum и трансляция

Независимо от цели транзакция всегда будет следовать базовой структуре с некоторыми конкретными полями данных -

  1. nonce: это количество транзакций, инициированных внешней учетной записью отправителя. Он определяет порядок, в котором выполняются транзакции со счета, и гарантирует, что выполнение транзакции происходит только один раз.
  2. gasLimit: это оценивает максимальное количество газа, которое потребуется для выполнения транзакции.
  3. gasPrice: определяет комиссию, которую отправитель готов платить за единицу газа, необходимую для выполнения транзакции.
  4. to: адрес учетной записи получателя транзакции. Как упоминалось ранее, для развертываний по контракту это поле установлено как null.
  5. value: средства, которые будут переведены от отправителя транзакции к получателю. Для контрактных развертываний это определяет начальный баланс для контрактного счета.
  6. data: содержит байт-код контракта для развертывания контракта или закодированные данные вызова выполнения метода.
  7. signature: 65-байтовая подпись ECDSA в R || S || Формат V.

Каждая новая отправленная транзакция проходит проверку значений, содержащихся в этих полях данных.

Например, отправленная транзакция отклоняется как недействительная узлом, на котором запущен клиент Geth, если -

  • значение одноразового номера транзакции слишком мало.
  • размер транзакции не превышает максимально допустимого лимита для предотвращения DoS-атак на сеть Ethereum.
  • сумма транзакции не может быть отрицательной. Транзакции, закодированные с помощью RLP, не являются отрицательными, но транзакция, созданная с использованием RPC, может иметь отрицательную стоимость транзакции.
  • для транзакции установлен расчетный лимит газа меньше, чем текущий лимит газа для блока.
  • подпись транзакции соответствует адресу подписавшего.
  • на счете подписывающей стороны достаточно средств для покрытия cost(=value + gas_price * gas_limit)
  • для транзакции было выделено достаточно газа, чтобы покрыть базовую комиссию за транзакцию.

Но транзакции, несмотря на то, что они действительны, могут быть не готовы к трансляции. В сеть Ethereum транслируются только те транзакции, которые «обрабатываются».

Обрабатываемые транзакции?

Проще говоря, транзакции, которые находятся в правильном порядке nonce, могут быть обработаны. Если последняя транзакция, ожидающая майнинга, имеет значение nonce x, следующая отправленная транзакция будет считаться обрабатываемой, если она имеет значение nonce x+1.

Все отправленные транзакции с nonce > x+1 помещаются в список очереди пула транзакций для узла. Поставленные в очередь транзакции становятся доступными для обработки только тогда, когда транзакция с nonce x+1 отправляется на узел Ethereum. Мы обсудим это более подробно в следующем разделе, где мы будем размышлять над любопытным случаем «зависания транзакций» в сети Ethereum.

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

Подтверждение транзакции

Любой узел в сети Ethereum, который может подтвердить набор транзакций путем добычи блока, можно назвать узлом майнера или просто майнером. Когда майнер выбирает ожидающую транзакцию для включения в блок, транзакция проходит следующие этапы:

  • Узел майнера проверяет транзакцию, как и все остальные узлы.
  • Транзакция выполняется вместе с другими транзакциями, выбранными для включения в блок.
  • Новый блок добывается после успешного завершения вычисления доказательства работы и объявляется.
  • Другие узлы в сети Ethereum проверяют полученный блок и выполняют все транзакции в блоке.
  • В конце концов узел, который транслировал эту транзакцию, получает блок и обновляет данные учетной записи контракта локально.
  • На этом этапе, когда выполняется вызов чтения для выборки точки данных, которая была обновлена ​​нашим вызовом записи, мы сможем получить обновленные данные.

Что произойдет, если транзакция не будет выполнена в какой-либо момент?

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

Любопытный случай зависания транзакций

Бывают случаи, когда транзакции Ethereum застревают. Это происходит при двух обстоятельствах -

  • Транзакции застряли в очереди пула транзакций
    В серии отправленных транзакций одна или несколько транзакций отклоняются. Это приводит к ситуации, когда все транзакции с одноразовыми номерами больше, чем неудачная, застревают в списке очереди пула транзакций. Когда новая транзакция заполняет этот «временной промежуток», эти застрявшие транзакции перемещаются из списка в очередь в список ожидающих транзакций.

  • Транзакции застряли в состоянии pending
    Транзакции, которые готовы к обработке / включению в блок майнерами, считаются находящимися в состоянии pending и хранятся в пуле транзакций. Однако, если для одной из этих транзакций установлена ​​низкая цена на газ, тогда эта транзакция и все последующие транзакции рискуют остаться в списке ожидания, пока майнер не решит включить транзакцию с низким содержанием газа.

Есть два способа открепить зависшие незавершенные транзакции:

  1. Отмена этих транзакций:
    Транзакция с определенным одноразовым номером, застрявшая в состоянии ожидания, может быть отменена путем отправки более дорогой транзакции с toaddress такой же, как fromaddress.
  2. Замена этих транзакций более высокой ценой на газ:
    Повышение цены должно соответствовать минимальному повышению цены, необходимому для замены исходной транзакции, в противном случае транзакция замены будет отклонена пулом транзакций клиента. . Это требование повышения цен также необходимо для отмены транзакций.

Невыполнение контракта

Подтвержденная транзакция в блокчейне Ethereum может не выполнить вызов метода в развернутом смарт-контракте или развернуть смарт-контракт по разным причинам:

  1. Ошибка неверной инструкции: это могло произойти в случае неверно закодированных данных ABI как части транзакции (неправильный селектор метода, недопустимые параметры и т. д.)
  2. Нет газа: на выполнение контракта может потребоваться больше газа, чем было выделено для сопутствующей транзакции. Это результат неправильной оценки газа на этапе создания транзакции.
  3. Внимание! Ошибка при выполнении контракта [Отменено]: Эта ошибка также часто встречается, когда во время выполнения вызова контракта возникают другие ошибки. Например: https://kovan.etherscan.io/tx/0x5f7628af46d9e72c6aaff2e606b38ee7debdeccb57b4efdcb11f6669aaa60eaa

Напомним из раздела «Подтверждение транзакции», что транзакции, которые не удалось выполнить, все еще включены в цепочку блоков.

Необходимость в менеджере транзакций

К настоящему времени должно быть очевидно, что для того, чтобы справиться с этим жизненным циклом, должен быть уровень управления транзакциями поверх таких клиентов, как Geth или Parity, чтобы

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

В следующей статье этой серии будет объяснено, как в BlockVigil мы работаем над реализацией отказоустойчивого самовосстанавливающегося диспетчера конечного автомата для транзакций Ethereum.

дальнейшее чтение

[1] « Как вообще работает Ethereum? »

[2] Эта статья о Транзакциях в Ethereum.

[3] Эта другая статья о Жизненном цикле транзакции Ethereum »