mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 09:23:48 +00:00
accounts, internal: return an error if no suitable estimated gas found
This commit is contained in:
parent
b81a9cd829
commit
e6a9ff9d4f
2 changed files with 54 additions and 23 deletions
|
|
@ -41,6 +41,7 @@ import (
|
||||||
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
||||||
|
|
||||||
var errBlockNumberUnsupported = errors.New("SimulatedBackend cannot access blocks other than the latest block")
|
var errBlockNumberUnsupported = errors.New("SimulatedBackend cannot access blocks other than the latest block")
|
||||||
|
var errGasEstimationFailed = errors.New("gas required exceeds block limit or always failing transaction")
|
||||||
|
|
||||||
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
|
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
|
||||||
// the background. Its main purpose is to allow easily testing contract bindings.
|
// the background. Its main purpose is to allow easily testing contract bindings.
|
||||||
|
|
@ -205,30 +206,46 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
||||||
|
|
||||||
// Binary search the gas requirement, as it may be higher than the amount used
|
// Binary search the gas requirement, as it may be higher than the amount used
|
||||||
var (
|
var (
|
||||||
lo uint64 = params.TxGas - 1
|
lo uint64 = params.TxGas - 1
|
||||||
hi uint64
|
hi, gasLimit uint64
|
||||||
)
|
)
|
||||||
if call.Gas != nil && call.Gas.Uint64() >= params.TxGas {
|
if call.Gas != nil && call.Gas.Uint64() >= params.TxGas {
|
||||||
hi = call.Gas.Uint64()
|
hi = call.Gas.Uint64()
|
||||||
} else {
|
} else {
|
||||||
hi = b.pendingBlock.GasLimit().Uint64()
|
hi = b.pendingBlock.GasLimit().Uint64()
|
||||||
}
|
}
|
||||||
for lo+1 < hi {
|
gasLimit = hi
|
||||||
// Take a guess at the gas, and check transaction validity
|
|
||||||
mid := (hi + lo) / 2
|
|
||||||
call.Gas = new(big.Int).SetUint64(mid)
|
|
||||||
|
|
||||||
|
// Determine whether the gas is adequate based on the result of the execution.
|
||||||
|
estimate := func(gas uint64) bool {
|
||||||
|
call.Gas = new(big.Int).SetUint64(gas)
|
||||||
snapshot := b.pendingState.Snapshot()
|
snapshot := b.pendingState.Snapshot()
|
||||||
_, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
_, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
||||||
b.pendingState.RevertToSnapshot(snapshot)
|
b.pendingState.RevertToSnapshot(snapshot)
|
||||||
|
|
||||||
// If the transaction became invalid or execution failed, raise the gas limit
|
|
||||||
if err != nil || failed {
|
if err != nil || failed {
|
||||||
lo = mid
|
return false
|
||||||
continue
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for lo+1 < hi {
|
||||||
|
// Take a guess at the gas, and check transaction validity
|
||||||
|
mid := (hi + lo) / 2
|
||||||
|
if !estimate(mid) {
|
||||||
|
// If the transaction became invalid or execution failed, raise the gas limit
|
||||||
|
lo = mid
|
||||||
|
} else {
|
||||||
|
// Otherwise assume the transaction succeeded, lower the gas limit
|
||||||
|
hi = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hi == gasLimit {
|
||||||
|
// Regard the transaction is invalid if the required gas exceeds block limit
|
||||||
|
// or simply a bad transaction. Since this type transaction will always fail.
|
||||||
|
if !estimate(hi) {
|
||||||
|
return nil, errGasEstimationFailed
|
||||||
}
|
}
|
||||||
// Otherwise assume the transaction succeeded, lower the gas limit
|
|
||||||
hi = mid
|
|
||||||
}
|
}
|
||||||
return new(big.Int).SetUint64(hi), nil
|
return new(big.Int).SetUint64(hi), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -653,8 +653,8 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr r
|
||||||
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) {
|
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) {
|
||||||
// Binary search the gas requirement, as it may be higher than the amount used
|
// Binary search the gas requirement, as it may be higher than the amount used
|
||||||
var (
|
var (
|
||||||
lo uint64 = params.TxGas - 1
|
lo uint64 = params.TxGas - 1
|
||||||
hi uint64
|
hi, gasLimit uint64
|
||||||
)
|
)
|
||||||
if (*big.Int)(&args.Gas).Uint64() >= params.TxGas {
|
if (*big.Int)(&args.Gas).Uint64() >= params.TxGas {
|
||||||
hi = (*big.Int)(&args.Gas).Uint64()
|
hi = (*big.Int)(&args.Gas).Uint64()
|
||||||
|
|
@ -666,20 +666,34 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*
|
||||||
}
|
}
|
||||||
hi = block.GasLimit().Uint64()
|
hi = block.GasLimit().Uint64()
|
||||||
}
|
}
|
||||||
|
gasLimit = hi
|
||||||
|
|
||||||
|
estimate := func(gas uint64) bool {
|
||||||
|
(*big.Int)(&args.Gas).SetUint64(gas)
|
||||||
|
_, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{})
|
||||||
|
if err != nil || failed {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
for lo+1 < hi {
|
for lo+1 < hi {
|
||||||
// Take a guess at the gas, and check transaction validity
|
// Take a guess at the gas, and check transaction validity
|
||||||
mid := (hi + lo) / 2
|
mid := (hi + lo) / 2
|
||||||
(*big.Int)(&args.Gas).SetUint64(mid)
|
if !estimate(mid) {
|
||||||
|
// If the transaction became invalid or execution failed, raise the gas limit
|
||||||
_, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{})
|
|
||||||
|
|
||||||
// If the transaction became invalid or execution failed, raise the gas limit
|
|
||||||
if err != nil || failed {
|
|
||||||
lo = mid
|
lo = mid
|
||||||
continue
|
} else {
|
||||||
|
// Otherwise assume the transaction succeeded, lower the gas limit
|
||||||
|
hi = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hi == gasLimit {
|
||||||
|
// Regard the transaction is invalid if the required gas exceeds block limit
|
||||||
|
// or simply a bad transaction. Since this type transaction will always fail.
|
||||||
|
if !estimate(hi) {
|
||||||
|
return nil, fmt.Errorf("gas required exceeds block limit or always failing transaction")
|
||||||
}
|
}
|
||||||
// Otherwise assume the transaction succeeded, lower the gas limit
|
|
||||||
hi = mid
|
|
||||||
}
|
}
|
||||||
return (*hexutil.Big)(new(big.Int).SetUint64(hi)), nil
|
return (*hexutil.Big)(new(big.Int).SetUint64(hi)), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue