hashgraph / hedera-services

Crypto, token, consensus, file, and smart contract services for the Hedera public ledger
Apache License 2.0
271 stars 121 forks source link

COST_ANSWER for ContractCallLocal does not match the actual fee and using its value directly results in INSUFFICIENT_TX_FEE #466

Open mehcode opened 4 years ago

mehcode commented 4 years ago

Summary of the defect

COST_ANSWER for ContractCallLocal does not match the actual fee and using its value directly results in INSUFFICIENT_TX_FEE.

Hedera transaction `0.0.1800@1598222633.779750518` failed pre-check with the status `INSUFFICIENT_TX_FEE`

How to reproduce (if possible)

Execute COST_ANSWER for a very simple ContractCallLocal. Then use that amount in a payment transaction for a ANSWER_ONLY ContractCallLocal without changing any other variables.

You can use the CreateStatefulContractExample example in the Java SDK but you'll need to remove our workaround for this issue in ContractCallQuery#getCostAsync.

Additional Context

The Java, Go, and JavaScript have historically always multiplied the cost from COST_ANSWER by 1.1, before using it in a payment transaction. Doing this, the problem goes away. But it seems like this problem has gotten worse as of the latest 0.7 testnet as the .Net SDK has also reported finding this.

My guess is whatever is happening is now also affecting the relatively simple queries and low gas costs that are normally used in SDK testing.

paulmadsenhed commented 4 years ago

The value returned by a COST_ANSWER for ContractCallLocal is an estimate, notably it uses a default size for the (predicted) returned data. If the actual size of returned data is much larger, then the estimated fee will be smaller than the required, and you'll get the INSUFFICIENT error.

qnswirlds commented 4 years ago

Our tests using https://github.com/hashgraph/hedera-services/tree/master/test-clients passed with a complete match of the cost returned in the ContractCallLocalQuery COST_ANSWER response. By complete match, I mean the ANSWER_ONLY query went through just fine with the exact returned cost from COST_ANSWER, or we received INSUFFICIENT_TX_FEE even when we deduct only 1 tinyBar from the returned cost. The tests were done both locally and against our current testnet.

@mehcode, could you please provide us a sample of ContractCallLocalQuery, both with COST_ANSWER and ANSWER_ONLY ResponseType that caused the mismatch, especially the Transaction as the payment in the QueryHeader? Thank you!

bugbytesinc commented 4 years ago

The value returned by a COST_ANSWER for ContractCallLocal is an estimate, notably it uses a default size for the (predicted) returned data. If the actual size of returned data is much larger, then the estimated fee will be smaller than the required, and you'll get the INSUFFICIENT error.

That is why the .net sdk had to add a feature to add "extra bytes returned gas" to a query contract call, this is to cover the unestimatable bytes fee. This is not a great workaround.

bugbytesinc commented 4 years ago

I also can't help but notice this was opened 8 days ago. TESTNET was failing all over the place with COST_ANSWER back then (including contract queries), unfortunately, by being reset, the edge case that caused whatever the problem has disappeared. Could it have been a caching problem with a gRPC service not being rebooted during upgrade (previewnet mirror node had a similar problem lately that was cleared up by recycling the gRPC service)