package ethapi import ( "context" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/rpc" "time" ) type PublicEthereum2API struct { b Backend } func NewEthereum2API(b Backend) *PublicEthereum2API { return &PublicEthereum2API{b} } func (s *PublicEthereum2API) Call(ctx context.Context, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (CallResult, error) { result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, vm.Config{}, 5*time.Second, s.b.RPCGasCap()) if err != nil { return CallResult{Success: false, Msg: err.Error()}, err } else { if len(result.Revert()) > 0 { revertErr := newRevertError(result) return CallResult{Success: false, Data: result.Revert(), Msg: revertErr.Error()}, nil } return CallResult{Success: true, Data: result.Return()}, nil } } // BatchCall executes a series of transactions on the state of a given block as base. // The base state can be overridden once before transactions are executed. // // Additionally, each call can override block context fields such as number. // // Note, this function doesn't make any changes in the state/blockchain and is // useful to execute and retrieve values. func (s *PublicEthereum2API) BatchCall(ctx context.Context, config BatchCallConfig) ([]CallResult, error) { state, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, config.Block) if state == nil || err != nil { return nil, err } // State overrides are applied once before all calls if err := config.StateOverrides.Apply(state); err != nil { return nil, err } // Setup context so it may be cancelled before the calls completed // or, in case of unmetered gas, setup a context with a timeout. var ( cancel context.CancelFunc //timeout = s.b.RPCEVMTimeout() timeout = time.Duration(5000000000) ) if timeout > 0 { ctx, cancel = context.WithTimeout(ctx, timeout) } else { ctx, cancel = context.WithCancel(ctx) } // Make sure the context is cancelled when the call has completed // this makes sure resources are cleaned up. defer cancel() var ( results []CallResult // Each tx and all the series of txes shouldn't consume more gas than cap globalGasCap = s.b.RPCGasCap() gp = new(core.GasPool).AddGas(globalGasCap) ) for _, call := range config.Calls { blockContext := core.NewEVMBlockContext(header, NewChainContext(ctx, s.b), nil) if call.BlockOverrides != nil { call.BlockOverrides.Apply(&blockContext) } result, doCallErr := doCall(ctx, s.b, call.CallArgs, state, header, timeout, gp, &blockContext) if doCallErr != nil { results = append(results, CallResult{Success: false, Msg: doCallErr.Error()}) } else { if len(result.Revert()) > 0 { revertErr := newRevertError(result) results = append(results, CallResult{Success: false, Data: result.Revert(), Msg: revertErr.Error()}) } else { results = append(results, CallResult{Success: true, Data: result.Return()}) } } } return results, nil }