¿Por qué mi TX falla debido a la falta de gas a pesar de que se suministró la cantidad correcta de gas?

Advertencia: Traté de proporcionar enlaces a mis transacciones y direcciones en etherscan.io, pero "necesito al menos 10 reputación para publicar más de 2 enlaces".

Tengo una cuenta que quiero barrer. Quiero barrer el ETH a un contrato de división de fondos (ETC/ETH). Solo me interesa barrer el saldo de ETH y mi objetivo es que la cuenta termine con un saldo de cero (por ejemplo, sin polvo).

Este es el contrato de división de fondos que estoy tratando de usar: 0x1e143b2588705dfea63a17f2032ca123df995ce0

Parece que el gas necesario para esta operación es de 29.717. Por ejemplo, aquí hay una transacción de muestra que envié al contrato, que según etherscan.io requería esa cantidad de gas: 0x7cd52325c0945d0de975a6713abdc50659c0c62ef523a1a99f2ad2a2d4128a8f

Sin embargo, si envío una transacción y limito la cantidad de gasolina a 29,717, mi transacción falla. Por ejemplo, aquí hay una transacción de muestra que envié al contrato con un límite de gas de 29,717, que falló por falta de gas: 0xcd31481b4dd9410daa22c8a47f9a4b29ef4a305877174eb346433bb4e6b03089(TX)

Descubrí que la cantidad mínima de gas que necesito especificar para que una de estas transferencias funcione es 31,991:

  • Transacción con 31,991 gas que funcionó: 0x7cd52325c0945d0de975a6713abdc50659c0c62ef523a1a99f2ad2a2d4128a8f(TX)
  • Transacción con 31,990 gas que falló: 0x8c92fde3cf07b3cdbf4dcc54ed6ccfb072f22933ab556612f3d23317a2466280(TX)

Sin embargo, cuando pasa el tx, parece que solo usó 29,717 de gas. Por ejemplo: la cuenta 0x19d90f1106c600bd8a70b5775776b4ecdc7a945b(dirección) tenía un saldo de 0.01282711 ETH(en el bloque 1964300).

Envié la transacción 0xb57c8b5aede3070e2fb80ea9a21ec43293cb5c7392ccb36357388422e9055509(TX) con los siguientes detalles:

  • Valor:0.01218729 ETH
  • Gas:31991
  • Precio de la gasolina:20000000000 Wei

Asi que:

  • Saldo antes de TX:0.01282711 ETH
  • Cantidad a enviar:0.01218729 ETH
  • Costo supuesto de TX: Gas* Price=0.00063982 ETH
  • Saldo - Monto a enviar - Supuesto costo de TX = ¡CERO!

Sin embargo, como puede ver, la cuenta 0x19d90f1106c600bd8a70b5775776b4ecdc7a945b(dirección) tiene un saldo de 0.00004548 ETH.

Esto, a su vez, significa que el costo real de TX fue 0.00059434 ETH: Costo real de TX = Saldo antes de TX - Importe enviado - Saldo final real = 0,01282711 - 0,01218729 - 0,00004548 = 0,00059434.

A un precio de gas de 20000000000 Wei, esto significa que la cantidad de gas utilizada fue: 29717(0.00059434/0.00000002 = 29717)

Entonces la pregunta es:

  1. ¿Por qué fallan las transacciones que especifican un límite de gas 29717?
  2. ¿Cómo barrido los fondos para que el saldo final de una cuenta ETH sea cero cuando uso el contrato anterior?

Información del sistema

Versión de Geth: 1.4.10-stable-c2eea630 SO y versión: Linux

Comportamiento esperado

La transacción 0x19d90f1106c600bd8a70b5775776b4ecdc7a945b debería haber sido exitosa.

Comportamiento real

La transacción 0x19d90f1106c600bd8a70b5775776b4ecdc7a945b falló debido a la falta de gas.

Pasos para reproducir el comportamiento

Use la transfer(address)función de contrato 0x1e143b2588705dfea63a17f2032ca123df995ce0enviando alguna cantidad y limite la cantidad de gas a29717

Aquí hay una transacción de muestra para este contrato que puede enviar a través de la API JSON-RPC:'{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from":"0xe7c7d161800ebb5112d7d892510e9f1dafc4010c","to":"0x1e143b2588705dfea63a17f2032ca123df995ce0","value":"0x1F99A58657EED0","data":"0x1a69523000000000000000000000000029d5527caa78f1946a409fa6acaf14a0a4a0274b"}],"id":6}'

Respuestas (1)

Comprender este rompecabezas puede ser instructivo. El comportamiento puede explicarse por la forma CALLen que funciona la instrucción en términos de gas.

Podemos comparar los rastros de VM de transacciones aquí:

(Los enlaces son para programar el contador justo antes de fallar CALL).

Consideremos ambas transacciones en paralelo, Aserá la transacción exitosa y Bla fallida. El valor es el gas restante en cualquier paso.

  1. Llamada de contrato: A = 31991, B = 29717.
  2. Antes incluso de que comience el contrato, 22680se consumen. A = 9311, B = 7037.
  3. Se realizan una serie de instrucciones que tienen un coste acumulado de 271.
  4. Antes de la transferencia real CALL, en el paso 65, estamos en A = 9040, B = 6766.
  5. En ese momento Bfalla porque no tiene suficiente gasolina para realizar la CALLinstrucción, que cuesta 9040 gas.
  6. Sin embargo, después de la llamada, 9040 gasno se han consumido por completo A: estamos de vuelta en 2300.
  7. Acontinúa sus operaciones hasta la última instrucción donde se encuentra en 2274.
  8. Los no utilizados 2274se reembolsan y el total de gas consumido es de hecho 31991-2274 = 29717.

Hay dos puntos que explican el comportamiento sorprendente.

  • El costo de una CALL de transferencia de valor es 40 + 9000. (según el apéndice G del Libro Amarillo ).
  • Se toma una cantidad de 2300 de gas de este costo y se envía al destinatario como gas .

El segundo punto es la clave. En el contexto de un contrato que llama a otro contrato, este llamado stipendse proporciona como gas mínimo para cubrir los costos operativos de una función de respaldo básica. Tenga en cuenta que también es posible reenviar manualmente más gas si se sabe que el destinatario tiene mayores necesidades.

En nuestro caso, dado que la cuenta del destinatario no es un contrato, stipendse reembolsó. En cierto sentido , el CALLcosto de la operación era solo 6740 gas, pero teníamos que demostrar que teníamos 9040que cubrir al menos el caso de un destinatario del contrato.

En versiones anteriores, todo el gas de la persona que llama se reenvía a la persona que recibe la llamada, pero esto estaba abierto al abuso y se implementó el nuevo comportamiento.

Más enlaces: