Это постоянно всплывает на форумах по мусору, поэтому я подумал, что задам и отвечу на этот вопрос: как узнать, что у вас кончился бензин?
В настоящее время нет четкого сигнала о том, что у вас закончился бензин. Сообщение журнала добавляется в какой-то будущий выпуск.
В настоящее время я проверяю, является ли 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);
});
}
Так как блок 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
нулевое значение.)
Подробнее здесь .
status
0 означает что-то еще, кроме 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 основных случая ошибок после майнинга транзакции
Для систематического использования этих случаев я обернул их в пакет 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 содержит номер блока), а также содержит газ, использованный так ясно, что во время генерации квитанции транзакция была запущена ... так почему квитанция не требует подтверждения завершена ли сделка? Кажется немного пугающим, что вызовы контрактов могут выполняться с такой малой видимостью относительно того, действительно ли состояние было обновлено в соответствии с ожидаемым поведением контракта.
эт
status
поле (я обновил свой ответ), и вам может быть интересно обновить код :)Пол С
эт
status
поле в Византии.