diff --git a/eth/api_simulation.go b/eth/api_simulation.go index 8c22b7329921..cdebabca6de1 100644 --- a/eth/api_simulation.go +++ b/eth/api_simulation.go @@ -15,7 +15,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/eth/gasestimator" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/common" @@ -506,56 +505,3 @@ func (b *SimulationAPIBackend) CallBundle(ctx context.Context, args CallBundleAr ret["bundleHash"] = "0x" + common.Bytes2Hex(bundleHash.Sum(nil)) return ret, nil } - -func (b *SimulationAPIBackend) EstimateGasBundle(ctx context.Context, args EstimateGasBundleArgs, overrides *ethapi.StateOverride) ([]uint64, error) { - txs := args.Transactions - - if b.stateDb == nil { - return nil, fmt.Errorf("statedb is empty") - } - - if b.currentBlock == nil { - return nil, fmt.Errorf("current block is empty") - } - - var ( - stateDB = b.stateDb.Copy() - parent = b.currentBlock.Header() - chainConfig = b.eth.BlockChain().Config() - gasCap = b.eth.Config().RPCGasCap - - opts = &gasestimator.Options{ - Config: chainConfig, - Chain: b.eth.BlockChain(), - Header: parent, - State: stateDB, - IsNotCopyStateDB: true, - ErrorRatio: estimateGasErrorRatio, - } - ) - if err := overrides.Apply(stateDB); err != nil { - log.Error("Failed to apply overrides to state db", "err", err) - return nil, err - } - - var gasEstimatedBundles []uint64 - - for _, tx := range txs { - // Run the gas estimation andwrap any revertals into a custom return - call, err := tx.ToMessage(gasCap, parent.BaseFee) - if err != nil { - return nil, err - } - estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap) - if err != nil { - if len(revert) > 0 { - return nil, newRevertError(revert) - } - return nil, err - } - - gasEstimatedBundles = append(gasEstimatedBundles, estimate) - } - - return gasEstimatedBundles, nil -} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 863849f4da6a..2463ccc0a39b 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1196,6 +1196,45 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr return hexutil.Uint64(estimate), nil } +func DoEstimateGasBundle(ctx context.Context, b Backend, bundle EstimateGasBundleArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, gasCap uint64) ([]hexutil.Uint64, error) { + // Retrieve the base state and mutate it with any overrides + stateDB, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + if stateDB == nil || err != nil { + return nil, err + } + if err = overrides.Apply(stateDB); err != nil { + return nil, err + } + // Construct the gas estimator option from the user input + opts := &gasestimator.Options{ + Config: b.ChainConfig(), + Chain: NewChainContext(ctx, b), + Header: header, + State: stateDB, + IsNotCopyStateDB: true, + ErrorRatio: estimateGasErrorRatio, + } + + estimateGas := make([]hexutil.Uint64, 0, len(bundle.Transactions)) + for _, args := range bundle.Transactions { + // Run the gas estimation andwrap any revertals into a custom return + call, err := args.ToMessage(gasCap, header.BaseFee) + if err != nil { + return nil, err + } + estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap) + if err != nil { + if len(revert) > 0 { + return nil, newRevertError(revert) + } + return nil, err + } + estimateGas = append(estimateGas, hexutil.Uint64(estimate)) + } + return estimateGas, nil + +} + // EstimateGas returns the lowest possible gas limit that allows the transaction to run // successfully at block `blockNrOrHash`, or the latest block if `blockNrOrHash` is unspecified. It // returns error if the transaction would revert or if there are unexpected failures. The returned @@ -1210,6 +1249,14 @@ func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, b return DoEstimateGas(ctx, s.b, args, bNrOrHash, overrides, s.b.RPCGasCap()) } +func (s *BlockChainAPI) EstimateGasBundle(ctx context.Context, args EstimateGasBundleArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) ([]hexutil.Uint64, error) { + bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) + if blockNrOrHash != nil { + bNrOrHash = *blockNrOrHash + } + return DoEstimateGasBundle(ctx, s.b, args, bNrOrHash, overrides, s.b.RPCGasCap()) +} + // RPCMarshalHeader converts the given header to the RPC output . func RPCMarshalHeader(head *types.Header) map[string]interface{} { result := map[string]interface{}{ diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 2751d5b5aae6..1b5ebd1589dd 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -76,6 +76,10 @@ type TransactionArgs struct { blobSidecarAllowed bool } +type EstimateGasBundleArgs struct { + Transactions []TransactionArgs `json:"transactions"` +} + // from retrieves the transaction sender address. func (args *TransactionArgs) from() common.Address { if args.From == nil { diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 1da7d737dd94..989cb790dc32 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -540,6 +540,11 @@ web3._extend({ inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputBlockNumberFormatter, null], outputFormatter: web3._extend.utils.toDecimal }), + new web3._extend.Method({ + name: 'estimateGasBundle', + call: 'eth_estimateGasBundle', + params: 3, + }), new web3._extend.Method({ name: 'submitTransaction', call: 'eth_submitTransaction',