From 94903d572b4ee72c7ea62ce9856f51def85fdd2a Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 24 Aug 2017 11:18:21 +0800 Subject: internal, accounts, eth: utilize vm failed flag to help gas estimation --- internal/ethapi/api.go | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'internal') diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index ab8478929..1ffb5a180 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -580,12 +580,12 @@ type CallArgs struct { Data hexutil.Bytes `json:"data"` } -func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, *big.Int, error) { +func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, *big.Int, bool, error) { defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr) if state == nil || err != nil { - return nil, common.Big0, err + return nil, common.Big0, false, err } // Set sender address or use a default if none specified addr := args.From @@ -623,7 +623,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr // Get a new instance of the EVM. evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg) if err != nil { - return nil, common.Big0, err + return nil, common.Big0, false, err } // Wait for the context to be done and cancel the evm. Even if the // EVM has finished, cancelling may be done (repeatedly) @@ -635,26 +635,28 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr // Setup the gas pool (also for unmetered requests) // and apply the message. gp := new(core.GasPool).AddGas(math.MaxBig256) - // TODO utilize failed flag to help gas estimation - res, gas, _, err := core.ApplyMessage(evm, msg, gp) + res, gas, failed, err := core.ApplyMessage(evm, msg, gp) if err := vmError(); err != nil { - return nil, common.Big0, err + return nil, common.Big0, false, err } - return res, gas, err + return res, gas, failed, err } // Call executes the given transaction on the state for the given block number. // It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values. func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { - result, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true}) + result, _, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true}) return (hexutil.Bytes)(result), err } // EstimateGas returns an estimate of the amount of gas needed to execute the given transaction. 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 - var lo, hi uint64 - if (*big.Int)(&args.Gas).Sign() != 0 { + var ( + lo uint64 = params.TxGas - 1 + hi uint64 + ) + if (*big.Int)(&args.Gas).Uint64() >= params.TxGas { hi = (*big.Int)(&args.Gas).Uint64() } else { // Retrieve the current pending block to act as the gas ceiling @@ -669,10 +671,10 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (* mid := (hi + lo) / 2 (*big.Int)(&args.Gas).SetUint64(mid) - _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{}) + _, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{}) - // If the transaction became invalid or used all the gas (failed), raise the gas limit - if err != nil || gas.Cmp((*big.Int)(&args.Gas)) == 0 { + // If the transaction became invalid or execution failed, raise the gas limit + if err != nil || failed { lo = mid continue } @@ -683,10 +685,11 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (* } // ExecutionResult groups all structured logs emitted by the EVM -// while replaying a transaction in debug mode as well as the amount of -// gas used and the return value +// while replaying a transaction in debug mode as well as transaction +// execution status, the amount of gas used and the return value type ExecutionResult struct { Gas *big.Int `json:"gas"` + Failed bool `json:"failed"` ReturnValue string `json:"returnValue"` StructLogs []StructLogRes `json:"structLogs"` } -- cgit v1.2.3