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:

up vote 38 down vote accepted

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.

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.

  • 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. – Thomas Jay Rush Oct 20 '17 at 13:47
  • I think that is what I said.... – Dave Appleton Nov 21 '17 at 12:01

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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