40

Pre Byzantium fork, I could use gas == gasUsed to detect when a transaction has failed (further details in How can the transaction status from a thrown error be detected when gas can be exactly the same as the gasUsed for a successful transaction?)

Post Byzantium fork, the revert opcode now returns a much lower gasUsed amount. How do I detect a failed transaction after the Byzantium fork?

See also:

2 Answers 2

46

Summary

After the Byzantium fork, eth.getTransactionReceipt(...) will return a status field. The status field has a value of 0 when a transaction has failed with the REVERT opcode and 1 when the transaction has succeeded.


Update Oct 10 2017

Responding to the comment by @thomas-jay-rush, when a transaction fails for a reason other than REVERT (i.e. THROW), the status field will have a value of 0 and gasUsed will be equal to gas. See tx 0xa0a5e34b as an example.



Details

I have configured the Byzantium block number in my dev blockchain using the following genesis.json:

{
  "config": {
    "homesteadBlock": 1,
    "byzantiumBlock": 12
  },
  "nonce": "0",
  "difficulty": "0x400",
  "mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578",
  "coinbase": "0x0000000000000000000000000000000000000000",
  "timestamp": "0x00",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "extraData": "0x",
  "gasLimit": "0x3B4A1B44",
  "alloc": {
    "0xa00af22d07c87d96eeeb0ed583f8f6ac7812827e": {
      "balance": "10000000000000000000000000"
    },
    "0xa11aae29840fbb5c86e6fd4cf809eba183aef433": {
      "balance": "10000000000000000000000000"
    }
  }
}

I can see the Byzantium fork is active in the following geth message:

INFO [10-09|23:30:37] Initialised chain configuration config="{ChainID: Homestead: 1 DAO: DAOSupport: false EIP150: EIP155: EIP158: Byzantium: 12 Engine: unknown}"


Failing Transactions Have A Transaction Receipt status Of 0x0

Here is the transaction receipt information from a failing transaction with the REVERT opcode:

> eth.getTransactionReceipt("0x6c039439191ed046f8d4a92734bb6c23b92c175df39ce2f089ac84c590b94918")
{
  blockHash: "0xf25b938c85772aa0abbbc9931e6da7a6e46c577619fb5004f2d85fdbe359eb60",
  blockNumber: 89,
  contractAddress: null,
  cumulativeGasUsed: 35983,
  from: "0xa11aae29840fbb5c86e6fd4cf809eba183aef433",
  gasUsed: 35983,
  ...
  status: "0x0",
  to: "0x0e946b999033257976aa5cbe0e3530618ca1582d",
  transactionHash: "0x6c039439191ed046f8d4a92734bb6c23b92c175df39ce2f089ac84c590b94918",
  transactionIndex: 0
}

The same status: "0x0" is returned when executing a throw instruction compiled with Solidity 0.4.11 .


Successful Transactions Have A Transaction Receipt status Of 0x1

And here is the transaction receipt information from a successful transaction:

> eth.getTransactionReceipt("0xbdacfebf6299a260adfa993421aeb26353aa2b4dd0e6f290d2acfd6a9b828a62")

{
  blockHash: "0xbda8b2d2850306e8a02be074f11ffe4f2243003df6e9c4adb1bbdcda1faf2e42",
  blockNumber: 87,
  contractAddress: null,
  cumulativeGasUsed: 126952,
  from: "0xa11aae29840fbb5c86e6fd4cf809eba183aef433",
  gasUsed: 126952,
  logs: [{
      address: "0x0e946b999033257976aa5cbe0e3530618ca1582d",
      blockHash: "0xbda8b2d2850306e8a02be074f11ffe4f2243003df6e9c4adb1bbdcda1faf2e42",
      blockNumber: 87,
      data: "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000",
      logIndex: 0,
      removed: false,
      topics: ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000a33a6c312d9ad0e0f2e95541beed0cc081621fd0", "0x000000000000000000000000a55a151eb00fded1634d27d1127b4be4627079ea"],
      transactionHash: "0xbdacfebf6299a260adfa993421aeb26353aa2b4dd0e6f290d2acfd6a9b828a62",
      transactionIndex: 0
  }, {
    ...
  }],
  ...
  status: "0x1",
  to: "0x0e946b999033257976aa5cbe0e3530618ca1582d",
  transactionHash: "0xbdacfebf6299a260adfa993421aeb26353aa2b4dd0e6f290d2acfd6a9b828a62",
  transactionIndex: 0
}

eth.getTransactionReceipt(...) pre-Byzantium fork does not include the status field.


Can The Status Be Anything Other Than Than Just 0 (Fail) And 1 (Success)?

From https://github.com/ethereum/go-ethereum/blob/master/core/types/receipt.go#L39-L42:

  • ReceiptStatusFailed = uint(0)
  • ReceiptStatusSuccessful = uint(1)

There is only be a status of failed (=0) or successful (=1).

See EIP 658: Embedding transaction return data in receipts for further information.


How Does EtherScan Currently Handle The Byzantium Fork Status On Ropsten?

Here's a transaction that is successfully executed - 0x142b8830

And here's a transaction that has failed using the REVERT opcode - 0x67a5f644

The failed transaction cannot be distinguished from the successful transaction in EtherScan currently, except that the failed transaction consumed less gas than the successful transaction, and the failed transaction did not log an event but the successful transaction did.

I've pinged EtherScan about this potential issue.

Update Oct 15 2017 There is now a TxReceipt Status: field on the EtherScan transaction page that displays Success or Fail.

6
  • Etherscan now supports this in the Byzantium activated ropsten: twitter.com/LefterisJP/status/917888899141300224
    – Lefteris
    Commented Oct 10, 2017 at 23:08
  • Nice! The txs I posted above have the blank TxReceipt Status fields. But it's there and should be good for new txs scanned by EtherScan. Commented Oct 10, 2017 at 23:20
  • We are reindexing the previous transactions, once this is completed it should show up on ropsten
    – mtbitcoin
    Commented Oct 12, 2017 at 7:37
  • Just checked it and the Fail is now displayed for my failed tx. Great. Commented Oct 12, 2017 at 13:41
  • There's something missing here. Maybe it just needs to be clarified. It says "The status field has a value of 0 when a transaction has failed with the REVERT opcode and 1 when the transaction has succeeded." This is silent about what happens when a transaction fails for reasons other than a REVERT (such as a THROW). Does status == 0 on a THROW as well as a REVERT or just a REVERT which is what this says. Commented Oct 21, 2017 at 22:06
0

Hate to tell you - but sometimes the used gas and the supplied gas are the same and it succeeded.

Can't remember which, think it was Parity - where the estimates are 100% accurate.

3
  • Yup. Details in ethereum.stackexchange.com/questions/6007/… Commented Oct 10, 2017 at 23:21
  • 1
    It doesn't really have anything to do with estimates. Even if the estimates were 100% accurate there would still be cases where gasUsed == gasAllowed ended in sucessfull transaction due to the simple fact that the exact same amount of gas was actually used as was supplied. For example in every simple transfer of ether from one external account to another where most wallets allow 21000 and exactly 21000 is consumed. Commented Oct 20, 2017 at 13:47
  • 1
    I think that is what I said.... Commented Nov 21, 2017 at 12:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.