Das taucht immer wieder in den Gitter-Foren auf, also dachte ich, ich stelle und beantworte diese Frage: Woher weißt du, dass dir das Benzin ausgegangen ist?
Es gibt derzeit kein klares Signal, dass Ihnen das Benzin ausgegangen ist. Einer zukünftigen Version wird eine Protokollnachricht hinzugefügt.
Derzeit überprüfe ich, ob gasSent == gasUsed ist. Dazu muss sich Ihr Code die Menge an Gas merken, die Sie bei einer bestimmten Transaktion gesendet haben, und warten, bis die Transaktion abgebaut wird. Wenn gasSent == gasUsed ist, ist Ihnen höchstwahrscheinlich das Benzin ausgegangen. In meinem Javascript-Code werfe ich eine Ausnahme. Das hat mir mehrere peinliche Forenbeiträge und einiges an Zeit erspart.
Theoretisch könnte die Transaktion abgebaut werden, wenn sie genau die verbrauchte Gasmenge benötigt. Ich kann mir jetzt keine Möglichkeit vorstellen, das herauszufinden, vielleicht könnte jemand diese Antwort ergänzen. Wenn Sie so nah am Rand des Benzinmangels sind, sollten Sie wahrscheinlich sowieso mehr Gas geben.
Ich biete kostenlos einen Code an, den ich verwendet habe, um die Web3-Funktionalität zu erweitern, die darauf wartet, dass eine Transaktion von einem lokalen Knoten abgebaut wird. Es verwendet Promises, aber die Anpassung an den Callback-Stil sollte nicht schwierig sein, wenn Sie keine Promises verwenden möchten. Ich plane, dies in Zukunft zu erweitern, um den Konsens mehrerer Knoten abzuwarten, aber ich werde das wahrscheinlich nicht teilen.
Sie können diesen Code nicht kopieren und in Ihren Code einfügen, wenn Sie kein Protokoll instanziiert oder eine Hilfsfunktion erstellt haben, um zu sehen, ob eine Variable festgelegt ist. Wenn Sie das noch nicht getan haben, sollten Sie...
Es sollte viel kleinerer Code sein, um dies für Contract-Contract-Aufrufe zu schreiben, daher werde ich dieses Beispiel nicht zeigen. Gleiches Konzept - prüfen Sie einfach, ob gasSent == gasUsed ist.
(Und ja, Promise-Fans, ich verwende ein Promise-Anti-Pattern. Ich bin nur nicht dazu gekommen, es neu zu schreiben. Die Funktionalität ist korrekt.)
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);
});
}
Da Block 4370000 (Byzanz) eth.getTransactionReceipt(transactionHash)
ein status
Feld zurückgibt, das einen Wert hat, 0
wann eine Transaktion fehlgeschlagen ist und 1
wann die Transaktion erfolgreich war.
Hier ist ein Beispiel, das das status
Feld zeigt:
{ 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 }
(Blöcke vor 4370000 haben einen status
Nullwert.)
Näheres hier .
status
von 0 etwas anderes als Out of Gas bedeutet, aber derzeit Menschen, die mit handgefertigten EVM-Baugruppen interagieren, sind selten. Trotzdem hilfreich, dass Sie darauf hinweisen, und eine Referenz für Fehler ist ethereum.github.io/yellowpaper/paper.pdf mit dem Suchbegriff „außergewöhnlich“.Hier ist mein Python-Code, um dies mit Populus und web3.py zu überprüfen :
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
Es gibt 2 Hauptfehlerfälle, nachdem eine Transaktion geschürft wurde
Zur systematischen Nutzung dieser Fälle habe ich diese in ein npm-Paket ethereum-web3-plus gepackt , wer will.
es wird so verwendet:
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);
} );
Vielleicht eine naive Frage - warum ist dies nicht nur als Markierung in der Transaktionsquittung enthalten. Die Quittung wird generiert, sobald der Block abgebaut ist (daher enthält die txn-Quittung die Blocknummer) und enthält auch das verbrauchte Gas, so dass zum Zeitpunkt der Generierung der Quittung die Transaktion ausgeführt wurde. Warum erfordert die Quittung also keine Bestätigung? davon, ob die Transaktion abgeschlossen ist? Scheint etwas beängstigend zu sein, dass Vertragsaufrufe mit so wenig Sichtbarkeit ausgeführt werden können, ob der Status tatsächlich gemäß dem erwarteten Vertragsverhalten aktualisiert wurde
eth
status
Feld (ich habe meine Antwort aktualisiert) und Sie könnten daran interessiert sein, den Code zu aktualisieren :)Paul S
eth
status
Feld in Byzanz überprüfen können.