I've seen some suggestions from the community about managing throws in transactions using some different methods:

  1. Don't use a throw - use events for error checking
  2. Check using eth_getTransactionReceipt that the gas used in the transaction was equal to the gas sent (this works except when the gas used was exactly the gas sent)
  3. Use eth_estimateGas on the transaction before sending it and checking that it doesn't return a value above some high limit (as used by chriseth in browser-solidity).

Assuming we want the state revert that comes with a throw, (1) is out. (2) and (3) will present problems when dealing with multiple transactions sent in a short period. For option (2), there is the problem that some transaction fails, and then all subsequent transactions are then buffered in a queue due to the nonce ordering requirements, and some filler transaction will need to be sent to plug the nonce gap. For option (3), we get the foresight of early detection, but with a drawback. EstimateGas, when used on a transaction that calls a contract method, will run in the current state (i.e. the last mined block). Consider the following:

  • Tx1 updates state to state B
  • Tx2 requires state B, otherwise throws

If we do the following in a short period (less than the time it takes for Tx1 to be mined):

  1. EstimateGas on Tx1, send Tx1
  2. EstimateGas on Tx2, send Tx2

Step (2) will result in the estimateGas throwing, where in reality Tx2 would not throw when it gets mined, because it would be executed after Tx1 (due to nonce ordering) and by then the state would have been updated.

Any ideas on how to manage this?

EDIT - just noticed the JSON RPC docs do specify that estimateGas can take a block param, so assuming we pass "pending", it should mitigate some of the problems with state updates, assuming transactions relevant are available to the node.

EDIT2 - the actual code for geth in api.go only actually takes one argument:

// EstimateGas returns an estimate of the amount of gas needed to execute the given transaction.
func (s *PublicBlockChainAPI) EstimateGas(args CallArgs) (*rpc.HexNumber, error) {
    _, gas, err := s.doCall(args, rpc.PendingBlockNumber)
    return rpc.NewHexNumber(gas), err

This is confirmed by the error returned when attempting to send the pending block as a parameter to the eth_estimateGas RPC endpoint "too many params, want 1 got 2". It looks like the go code actually injects the pending block as the block parameter argument.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.