¿Cómo detecto una transacción fallida después de la bifurcación de Byzantium ya que el código de operación REVERT no consume todo el gas?

Pre bifurcación de Bizancio, podría usar gas == gasUsedpara detectar cuando una transacción ha fallado (más detalles en ¿Cómo se puede detectar el estado de la transacción de un error lanzado cuando el gas puede ser exactamente el mismo que el gas utilizado para una transacción exitosa? )

Después de la bifurcación de Byzantium, el código de operación de reversión ahora devuelve una cantidad de gas utilizada mucho menor. ¿Cómo detecto una transacción fallida después de la bifurcación de Bizancio?

Ver también:

Respuestas (2)

Resumen

Después de la bifurcación de Bizancio, eth.getTransactionReceipt(...)devolverá un statuscampo. El campo de estado tiene un valor de 0cuando una transacción ha fallado con el REVERTcódigo de operación y 1cuando la transacción ha tenido éxito.


Actualización 10 de octubre de 2017

Respondiendo al comentario de @thomas-jay-rush, cuando una transacción falla por un motivo que no sea REVERT(es decir THROW), el campo de estado tendrá un valor de 0y gasUsedserá igual a gas. Consulte tx 0xa0a5e34b como ejemplo.



Detalles

Configuré el número de bloque de Byzantium en mi cadena de bloques de desarrollo usando lo siguiente 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"
    }
  }
}

Puedo ver que la bifurcación de Byzantium está activa en el siguiente gethmensaje:

INFO [10-09|23:30:37] Configuración de cadena inicializada config="{ChainID: Homestead: 1 DAO: DAOSupport: false EIP150: EIP155: EIP158: Byzantium: 12 Engine: unknown}"


Las transacciones fallidas tienen un recibo de transacción statusde0x0

Aquí está la información del recibo de la transacción de una transacción fallida con el REVERTcódigo de operación:

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

Lo mismo status: "0x0"se devuelve al ejecutar una throwinstrucción compilada con Solidity 0.4.11.


Las transacciones exitosas tienen un recibo de transacción statusde0x1

Y aquí está la información del recibo de transacción de una transacción exitosa:

> 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(...)La horquilla anterior a Bizancio no incluye el statuscampo.


¿Puede el estado ser algo más que 0 (Falla) y 1 (Éxito)?

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

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

Solo hay un estado de fallido (=0) o exitoso (=1).

Consulte EIP 658: Incorporación de datos de devolución de transacciones en recibos para obtener más información.


¿Cómo maneja EtherScan actualmente el estado de la bifurcación de Byzantium en Ropsten?

Aquí hay una transacción que se ejecutó con éxito: 0x142b8830

Y aquí hay una transacción que falló al usar el REVERTcódigo de operación: 0x67a5f644

La transacción fallida no se puede distinguir de la transacción exitosa en EtherScan actualmente, excepto que la transacción fallida consumió menos gas que la transacción exitosa y la transacción fallida no registró un evento pero la transacción exitosa sí.

Hice ping a EtherScan sobre este problema potencial.

Actualización del 15 de octubre de 2017 Ahora hay un campo TxReceipt Status: en la página de transacciones de EtherScan que muestra Success or Fail .

Etherscan ahora admite esto en el ropsten activado por Byzantium: twitter.com/LefterisJP/status/917888899141300224
¡Agradable! Los txs que publiqué anteriormente tienen los campos de estado de TxReceipt en blanco. Pero está ahí y debería ser bueno para los nuevos tx escaneados por EtherScan.
Estamos reindexando las transacciones anteriores, una vez que esto se complete, debería aparecer en ropsten
Acabo de comprobarlo y ahora se muestra el error para mi tx fallido. Excelente.
Aquí falta algo. Tal vez sólo necesita ser aclarado. Dice "El campo de estado tiene un valor de 0 cuando una transacción ha fallado con el código de operación REVERT y 1 cuando la transacción ha tenido éxito". Esto no dice nada sobre lo que sucede cuando una transacción falla por razones distintas a una REVERT (como un LANZAMIENTO). ¿Tiene el estado == 0 en un LANZAMIENTO, así como un REVERT o simplemente REVERT, que es lo que dice esto.
Se agregó información sobre el estado de un TIRADO. Gracias @TJR

Odio decírtelo, pero a veces el gas usado y el gas suministrado son los mismos y tuvo éxito.

No puedo recordar cuál, creo que fue Parity, donde las estimaciones son 100% precisas.

Realmente no tiene nada que ver con las estimaciones. Incluso si las estimaciones fueran 100 % precisas, todavía habría casos en los que gasUsed == gasAllowed terminó en una transacción exitosa debido al simple hecho de que se usó exactamente la misma cantidad de gas que se suministró. Por ejemplo, en cada simple transferencia de ether de una cuenta externa a otra donde la mayoría de las billeteras permiten 21000 y se consumen exactamente 21000.
Creo que eso es lo que dije....