From aedf42a1551faf6aef5e88a27d2cefe437226bed Mon Sep 17 00:00:00 2001 From: Zhang Guyu Date: Tue, 11 Oct 2022 11:49:11 +0800 Subject: [PATCH] feat: `gasUsed` use `result.UsedGas` (#45) --- eth/api_pre_exec.go | 147 -------------------------------------------- 1 file changed, 147 deletions(-) diff --git a/eth/api_pre_exec.go b/eth/api_pre_exec.go index 7acc332761..1c841baed7 100644 --- a/eth/api_pre_exec.go +++ b/eth/api_pre_exec.go @@ -2,7 +2,6 @@ package eth import ( "context" - "errors" "fmt" "hash" "math" @@ -19,8 +18,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/internal/ethapi" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" // "github.com/DeBankDeFi/eth/txtrace" @@ -249,7 +246,6 @@ func (api *PreExecAPI) TraceMany(ctx context.Context, origins []PreArgs) ([]PreR return nil, err } for i := 0; i < len(origins); i++ { - stateOld := state.Copy() origin := origins[i] if origin.Nonce == nil { preResList = append(preResList, PreResult{ @@ -347,150 +343,7 @@ func (api *PreExecAPI) TraceMany(ctx context.Context, origins []PreArgs) ([]PreR Msg: (preRes.Trace)[0].Error, } } - if preRes.Error.Code == 0 { - gasLimit := header.GasLimit - gasCap := api.e.APIBackend.RPCGasCap() - if gasLimit > gasCap { - gasLimit = gasCap - } - usedGas := api.doEstimateGas(ctx, txArgs, header, stateOld, gasLimit) - log.Debug("doEstimateGas", "usedGas", usedGas) - if usedGas > 0 { - preRes.GasUsed = usedGas - } - } preResList = append(preResList, preRes) } return preResList, nil } - -func (api *PreExecAPI) doEstimateGas(ctx context.Context, args ethapi.TransactionArgs, header *types.Header, state *state.StateDB, gasLimit uint64) uint64 { - // Binary search the gas requirement, as it may be higher than the amount used - var ( - lo uint64 = params.TxGas - 1 - hi uint64 - ) - // Use zero address if sender unspecified. - if args.From == nil { - args.From = new(common.Address) - } - // Determine the highest gas limit can be used during the estimation. - if args.Gas != nil && uint64(*args.Gas) >= params.TxGas { - hi = uint64(*args.Gas) - } else { - hi = gasLimit - } - // Normalize the max fee per gas the call is willing to spend. - var feeCap *big.Int - if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { - return 0 - } else if args.GasPrice != nil { - feeCap = args.GasPrice.ToInt() - } else if args.MaxFeePerGas != nil { - feeCap = args.MaxFeePerGas.ToInt() - } else { - feeCap = common.Big0 - } - // Recap the highest gas limit with account's available balance. - if feeCap.BitLen() != 0 { - balance := state.GetBalance(*args.From) // from can't be nil - available := new(big.Int).Set(balance) - if args.Value != nil { - if args.Value.ToInt().Cmp(available) >= 0 { - return 0 - } - available.Sub(available, args.Value.ToInt()) - } - allowance := new(big.Int).Div(available, feeCap) - - // If the allowance is larger than maximum uint64, skip checking - if allowance.IsUint64() && hi > allowance.Uint64() { - transfer := args.Value - if transfer == nil { - transfer = new(hexutil.Big) - } - log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance, - "sent", transfer.ToInt(), "maxFeePerGas", feeCap, "fundable", allowance) - hi = allowance.Uint64() - } - } - // Recap the highest gas allowance with specified gascap. - if gasLimit != 0 && hi > gasLimit { - hi = gasLimit - } - cap := hi - - // Create a helper to check if a gas allowance results in an executable transaction - executable := func(gas uint64) (bool, *core.ExecutionResult, error) { - args.Gas = (*hexutil.Uint64)(&gas) - - result, err := api.doCallCopy(ctx, args, header, state) - log.Debug("doCallCopy", "result", result, "err", err) - if err != nil { - if errors.Is(err, core.ErrIntrinsicGas) { - return true, nil, nil // Special case, raise gas limit - } - return true, nil, err // Bail out - } - return result.Failed(), result, nil - } - - // Execute the binary search and hone in on an executable gas limit - for lo+1 < hi { - mid := (hi + lo) / 2 - failed, _, err := executable(mid) - - // If the error is not nil(consensus error), it means the provided message - // call or transaction will never be accepted no matter how much gas it is - // assigned. Return the error directly, don't struggle any more. - if err != nil { - return 0 - } - if failed { - lo = mid - } else { - hi = mid - } - } - // Reject the transaction as invalid if it still fails at the highest allowance - if hi == cap { - failed, result, err := executable(hi) - if err != nil { - return 0 - } - if failed { - if result != nil && result.Err != vm.ErrOutOfGas { - if len(result.Revert()) > 0 { - return 0 - } - return 0 - } - // Otherwise, the specified gas cap is too low - return 0 - } - } - return hi -} - -func (api *PreExecAPI) doCallCopy(ctx context.Context, args ethapi.TransactionArgs, header *types.Header, state *state.StateDB) (*core.ExecutionResult, error) { - stateNew := state.Copy() - // Get a new instance of the EVM. - msg, err := args.ToMessage(api.e.APIBackend.RPCGasCap(), header.BaseFee) - if err != nil { - return nil, err - } - evm, vmError, err := api.e.APIBackend.GetEVM(ctx, msg, stateNew, header, &vm.Config{NoBaseFee: true}) - if err != nil { - return nil, err - } - // Execute the message. - gp := new(core.GasPool).AddGas(math.MaxUint64) - result, err := core.ApplyMessage(evm, msg, gp) - if err := vmError(); err != nil { - return nil, err - } - if err != nil { - return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.Gas()) - } - return result, nil -}