Как я узнаю, что у меня кончился газ программно?

Это постоянно всплывает на форумах по мусору, поэтому я подумал, что задам и отвечу на этот вопрос: как узнать, что у вас кончился бензин?

Ответы (5)

В настоящее время нет четкого сигнала о том, что у вас закончился бензин. Сообщение журнала добавляется в какой-то будущий выпуск.

В настоящее время я проверяю, является ли gasSent == gasUsed. Это требует, чтобы ваш код запоминал количество газа, которое вы отправили на конкретную транзакцию, и ждал, пока транзакция будет добыта. Если gasSent == gasUsed, у вас, скорее всего, закончился бензин. В моем коде javascript я выбрасываю исключение. Это сэкономило мне несколько неловких постов на форуме и немало времени.

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

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

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

Для написания этого кода для вызовов контракт-контракт должен быть намного меньше кода, поэтому я не буду показывать этот пример. Та же концепция - просто проверьте, если gasSent == gasUsed.

(И да, поклонники Promise, я использую анти-шаблон обещания. Я просто не удосужился его переписать. Функциональность правильная.)

Object.getPrototypeOf(web3.eth).awaitConsensus = function(txhash, gasSent) {
var deferred = Promise.pending();
ethP = this;
filter = this.filter('latest');         // XXX make async
callstack = new Error().stack;
filter.watch(function(error, result) {
    // this callback is called multiple times, so can't promise-then it
    ethP.getTransactionReceiptAsync(txhash).then(function(receipt)  {
    // XXX should probably only wait max 2 events before failing XXX 
    if (receipt && receipt.transactionHash == txhash) {
        filter.stopWatching();
        log.info({txreceipt: receipt});

        if (js.isSet(gasSent)) {
            // note corner case of gasUsed == gasSent.  It could
            // mean used EXACTLY that amount of gas and succeeded.
            // this is a limitation of ethereum.  Hopefully they fix it
            if (receipt.gasUsed >= gasSent) {
                log.error({ badReceipt: receipt });
                log.error({ originalStack: callstack });
                throw(Error("ran out of gas, transaction likely failed!"
                                                                + callstack));
            }
        }

        deferred.resolve(receipt);
    }
    });
});
return deferred.promise.timeout(60000, "awaitConsensus timed out after 60000ms")
        .catch(function(e) {
            log.error(e);
            process.exit(1);
        });

}

В квитанциях теперь есть statusполе (я обновил свой ответ), и вам может быть интересно обновить код :)
Да, многие вещи устаревают в web3.js v1.0, вероятно, благодаря большому количеству отзывов на этом форуме. Не знаю, что с ними делать. Возможно, следует начать мета-обсуждение, а не по одному для каждого соответствующего вопроса.
Хорошее замечание по поводу web3.js v1.0 и публикации его в мета. Мой комментарий здесь заключался в том, что вы можете удалить таймер и просто проверить statusполе в Византии.

Так как блок 4370000 (Byzantium) eth.getTransactionReceipt(transactionHash)будет возвращать statusполе, которое имеет значение, 0когда транзакция не удалась и 1когда транзакция прошла успешно.

Вот пример, показывающий statusполе:

{ blockHash: '0xb1fcff633029ee18ab6482b58ff8b6e95dd7c82a954c852157152a7a6d32785e',
  blockNumber: 4370000,
  contractAddress: null,
  cumulativeGasUsed: 21000,
  gasUsed: 21000,
  logs: [],
  logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
  root: null,
  status: 1, // **** HERE IS THE STATUS FIELD *****
  transactionHash: '0x1421a887a02301ae127bf2cd4c006116053c9dc4a255e69ea403a2d77c346cf5',
  transactionIndex: 0 }

(Блоки до 4370000 будут иметь statusнулевое значение.)

Подробнее здесь .

Я использую web3j. Ни квитанция транзакции, ни объект транзакции не имеют статуса поля.
@rahul Я не уверен в статусе реализации Java, поскольку в первую очередь это усилия сообщества; предложение состоит в том, чтобы зарегистрировать проблему в их репозитории Github.
есть ли другие причины, по которым транзакция может завершиться неудачно, помимо газа? Если это так, то есть еще некоторые дополнительные проверки для определения причины сбоя транзакции.
@PaulS Другие ошибки, например неверный код операции, не возникнут, если используется достойный компилятор ethereum.stackexchange.com/questions/2307/… Да, возможно, что status0 означает что-то еще, кроме Out of Gas, но в настоящее время люди, взаимодействующие с ручной сборкой EVM, встречаются редко. Тем не менее полезно, чтобы вы указали на это, и ссылка на ошибки: ethereum.github.io/yellowpaper/paper.pdf с поисковым запросом «исключительно».

Вот мой код Python, чтобы проверить это с помощью Populus и web3.py :

from web3 import Web3
from populus.utils.transactions import wait_for_transaction_receipt

class TransactionConfirmationError(Exception):
    """A transaction was not correctly included in blockchain."""


def confirm_transaction(web3: Web3, txid: str, timeout=60) -> dict:
    """Make sure a transaction was correctly performed.

    Confirm that

    * The transaction has been mined in blockchain

    * The transaction did not throw an error (used up all its gas)

    http://ethereum.stackexchange.com/q/6007/620

    :raise TransactionConfirmationError: If we did not get it confirmed in time
    :return: Transaction receipt
    """

    try:
        receipt = wait_for_transaction_receipt(web3, txid, timeout)
    except Timeout as e:
        raise TransactionConfirmationError("Could not confirm tx {} within timeout {}".format(txid, timeout)) from e

    tx = web3.eth.getTransaction(txid)

    if tx["gas"] == receipt["gasUsed"]:
        raise TransactionConfirmationError("Transaction failed (out of gas, thrown): {}".format(txid))

    return receipt

Есть 2 основных случая ошибок после майнинга транзакции

  • у EVM кончился газ: действительно, лучший способ проверить это gasUsed==gas
  • развернутый контракт не удалось развернуть: getCode(address)==0x

Для систематического использования этих случаев я обернул их в пакет npm ethereum-web3-plus для тех, кто хочет.

он используется так:

web3.waitFor(  web3.newInstanceTx("Example"), // your txHash
             function(tx, contract, error) {
                  console.log("callback:", tx, contract, error);
                  // Possible errors : full gas used: <gas used>
                  //                   created contract has no bytecodes
                  if(contract) E = web3.instanceAt("Example", contract);
             } );

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

Всем привет. Боюсь, вам нужно будет задать это как отдельный вопрос, а не публиковать как ответ на существующий вопрос.
Добро пожаловать в Эфириум! Если у вас есть другой вопрос, пожалуйста, задайте его, нажав кнопку « Задать вопрос» .