0

This transaction failed without reason, https://blockscout.com/etc/mainnet/tx/0x58c0a6880fcf5a04957384768865966a05869d864932ab88b7a5ae3491191db5/internal-transactions.

I don't think it ran out of gas, since the computation uses 70% of the GAS provided. And worked the next time I tried, no parameters changed except different blockhash in random number generator. I see nothing wrong with the code. And I re-ran the function in Remix a dozen times, it works.

The only reason I could see, is if the state "lagged", that the state transition that happened 4 blocks earlier (that was necessary to pass a check in the function) somehow was not accounted for in the transaction. But if the miner "artificially" failed it because they didn't keep track of the state, this must mean that the majority of miners agreed with that, or the block would have been rejected. That should not happen unless the majority of miners are corrupt.

So I don't know why it failed. Anyone have any insight to why it failed? This might not be the place to ask for transaction debugging, but it was recommended to do so here: Debugging a failed transaction.

Johan
  • 11
  • 1
  • There is a previous Register transaction that uses more than 100k gas. I'd say that is the most probable cause. – Ismael Oct 21 '21 at 02:10
  • thanks for reply. the first register() transaction has higher gas cost for registry[t].push() operation since it sets array length from zero to non-zero, more expensive than non-zero to non-zero, https://www.reddit.com/r/ethereum/comments/4usq1q/is_the_cost_of_arraypush_a_constant/ – Johan Oct 21 '21 at 02:36
  • but you are right that it might be that there are two ways register() can be processed. inserting at last position, or at any other position. seems to have 10000 lower gas cost for the "insert at last position". maybe it was just that. still looks like there should be enough gas. – Johan Oct 21 '21 at 02:47
  • in Remix, first register costs 115k for me, and then 81k vs 91k depending on insert type. in the deployed contract, first transaction is 105k, then 71k for the one that worked, but 88k used for the one that failed. looks like there should be enough gas.

    these ones state out of gas, https://etc.tokenview.com/en/tx/0x58c0a6880fcf5a04957384768865966a05869d864932ab88b7a5ae3491191db5 https://explorer.bitquery.io/ethclassic/tx/0x58c0a6880fcf5a04957384768865966a05869d864932ab88b7a5ae3491191db5

    – Johan Oct 21 '21 at 03:11
  • If it somehow costs >88k while executing, but would end up at 81k after execution finishes, it makes sense. The gas estimate differs from 88k and 98k depending on insert type. – Johan Oct 21 '21 at 03:59
  • I double-checked now, and, the transaction only uses 81k gas. The one that failed, was given 88k because it estimated it with current blockhash for random function, that would have caused insert at end type register() with gas cost 71k. and because gas cost was the more expensive alternative, it failed. but, why does 88k gas fail when end cost is just 81k? – Johan Oct 21 '21 at 04:20
  • ok. the less expensive type, does a lot of setting variables to 0. this has negative gas cost. but, "gas refund is provided only 1 time, at the very end of the transaction's execution" and therefore "a transaction cannot use its own gas refund to pay for any part of its execution" (source: https://ethereum.stackexchange.com/a/3969). I now understand the why it failed. thanks for all the help, was very helpful, would have taken me a lot longer otherwise. – Johan Oct 21 '21 at 04:43
  • 1
    posted it all as answers. big thanks. peace. – Johan Oct 21 '21 at 04:54
  • Exactly, gas has to be enougth to execute the whole transaction, even when some is refunded at the end. If the transaction fail for any reason, like out of gas, there is no refund. – Ismael Oct 21 '21 at 05:36
  • Do you happen to know where the negative gas cost happens? I'm guessing it is at the registry[t].push(), pushing a 0 value, then setting that value to non-zero later on in function. – Johan Oct 21 '21 at 05:39
  • In ETH after London fork is quite complicated, see EIP 3529. – Ismael Oct 21 '21 at 05:53
  • that is irrelevant to the question. usually when sharing irrelevant things, it is because you lack understanding of the issue. back to the topic, my first assumption was wrong. it is actually the deductToken() function that has a refund. it changes balanceOf from 1 to 0 in that transaction. well, found it at last, and you helped me get started, so thanks again. – Johan Oct 21 '21 at 06:04

1 Answers1

1

It fails for two reasons. First, like Ismael pointed out accurately, it is an out of gas error. The reason the gas was estimated wrongly, was because the function has two distinct gas costs, depending on random number generated, one more expensive than the other. The gas cost estimated was using the blockhash read at the time of estimating that triggered the cheaper type of the function. But, the blockhash during actual execution on-chain, triggered the more expensive type. There would still have been enough gas, when refunds from negative gas costs were factored in, but, those refunds are given at the end of the transaction (source), so during execution the gas cost exceeded the supplied gas.

Examples showing the different gas costs, this transaction was the one that was failed. It was given 88k gas and it costs 81k gas. This transactions shows that gas estimates for the more expensive (81k) type of computation in the function has an estimate for 98k. And, that the cheaper type costs 71k gas and has gas estimate of 88k can be seen here.

Big thanks to Ismael for pointing me in the right direction. It was actually pretty complex reason for failing.

Johan
  • 11
  • 1