code: func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) {
  	b.mu.Lock()
  	defer b.mu.Unlock()
  
  	// Determine the lowest and highest possible gas limits to binary search in between
  	var (
  		lo  uint64 = params.TxGas - 1
  		hi  uint64
  		cap uint64
  	)
  	if call.Gas >= params.TxGas {
  		hi = call.Gas
  	} else {
  		hi = b.pendingBlock.GasLimit()
  	}
  	cap = hi
  
  	// Create a helper to check if a gas allowance results in an executable transaction
  	executable := func(gas uint64) bool {
  		call.Gas = gas
  
  		snapshot := b.pendingState.Snapshot()
  		_, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
  		b.pendingState.RevertToSnapshot(snapshot)
  
  		if err != nil || failed {
  			return false
  		}
  		return true
  	}
  	// Execute the binary search and hone in on an executable gas limit
  	for lo+1 < hi {
  		mid := (hi + lo) / 2
  		if !executable(mid) {
  			lo = mid
  		} else {
  			hi = mid
  		}
  	}
  	// Reject the transaction as invalid if it still fails at the highest allowance
  	if hi == cap {
  		if !executable(hi) {
  			return 0, errGasEstimationFailed
  		}
  	}
  	return hi, nil
  }
docs: // EstimateGas executes the requested code against the currently pending block/state and
  // returns the used amount of gas.