Browse Source

能batch call,可用性未知

skyfffire 2 năm trước cách đây
mục cha
commit
7dea05fd67

+ 2 - 0
core/vm/evm.go

@@ -102,6 +102,8 @@ type BlockContext struct {
 	BlockNumber *big.Int       // Provides information for NUMBER
 	Time        *big.Int       // Provides information for TIME
 	Difficulty  *big.Int       // Provides information for DIFFICULTY
+	BaseFee     *big.Int       // Provides information for BASEFEE
+	Random      *common.Hash   // Provides information for RANDOM
 }
 
 // TxContext provides the EVM with information about a transaction.

+ 86 - 0
internal/ethapi/api.go

@@ -954,6 +954,92 @@ func doCall(ctx context.Context, b Backend, args CallArgs, state *state.StateDB,
 	return result, nil
 }
 
+// BatchCallConfig is the config object to be passed to eth_batchCall.
+type BatchCallConfig struct {
+	Block          rpc.BlockNumberOrHash
+	StateOverrides *StateOverride
+	Calls          []BatchCallArgs
+}
+
+// BatchCallArgs is the object specifying each call within eth_batchCall. It
+// extends TransactionArgs with the list of block metadata overrides.
+type BatchCallArgs struct {
+	CallArgs
+	BlockOverrides *BlockOverrides
+}
+
+// CallResult is the result of one call.
+type CallResult struct {
+	Return hexutil.Bytes
+	Error  error
+}
+
+// BlockChainAPI provides an API to access Ethereum blockchain data.
+type BlockChainAPI struct {
+	b Backend
+}
+
+// NewBlockChainAPI creates a new Ethereum blockchain API.
+func NewBlockChainAPI(b Backend) *BlockChainAPI {
+	return &BlockChainAPI{b}
+}
+
+// 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 *BlockChainAPI) 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, err := doCall(ctx, s.b, call.CallArgs, state, header, timeout, gp, &blockContext)
+		if err != nil {
+			return nil, err
+		}
+		// If the result contains a revert reason, try to unpack it.
+		if len(result.Revert()) > 0 {
+			result.Err = newRevertError(result)
+		}
+		results = append(results, CallResult{Return: result.Return(), Error: result.Err})
+	}
+	return results, nil
+}
+
 func newRevertError(result *core.ExecutionResult) *revertError {
 	reason, errUnpack := abi.UnpackRevert(result.Revert())
 	err := errors.New("execution reverted")

+ 1 - 2
internal/ethapi/backend.go

@@ -19,8 +19,6 @@ package ethapi
 
 import (
 	"context"
-	"math/big"
-
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/consensus"
@@ -34,6 +32,7 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rpc"
+	"math/big"
 )
 
 // Backend interface provides the common API services (that are provided by

+ 46 - 0
internal/ethapi/block_overrides.go

@@ -0,0 +1,46 @@
+package ethapi
+
+import (
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/hexutil"
+	"github.com/ethereum/go-ethereum/core/vm"
+)
+
+// BlockOverrides is a set of header fields to override.
+type BlockOverrides struct {
+	Number     *hexutil.Big
+	Difficulty *hexutil.Big
+	Time       *hexutil.Big
+	GasLimit   *hexutil.Uint64
+	Coinbase   *common.Address
+	Random     *common.Hash
+	BaseFee    *hexutil.Big
+}
+
+// Apply overrides the given header fields into the given block context.
+func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
+	if diff == nil {
+		return
+	}
+	if diff.Number != nil {
+		blockCtx.BlockNumber = diff.Number.ToInt()
+	}
+	if diff.Difficulty != nil {
+		blockCtx.Difficulty = diff.Difficulty.ToInt()
+	}
+	if diff.Time != nil {
+		blockCtx.Time = diff.Time.ToInt()
+	}
+	if diff.GasLimit != nil {
+		blockCtx.GasLimit = uint64(*diff.GasLimit)
+	}
+	if diff.Coinbase != nil {
+		blockCtx.Coinbase = *diff.Coinbase
+	}
+	if diff.Random != nil {
+		blockCtx.Random = diff.Random
+	}
+	if diff.BaseFee != nil {
+		blockCtx.BaseFee = diff.BaseFee.ToInt()
+	}
+}

+ 5 - 0
internal/web3ext/web3ext.go

@@ -587,6 +587,11 @@ web3._extend({
 			params: 2,
 			inputFormatter: [null, web3._extend.formatters.inputBlockNumberFormatter],
 		}),
+		new web3._extend.Method({
+			name: 'batchCall',
+			call: 'eth_batchCall',
+			params: 1,
+		}),
 	],
 	properties: [
 		new web3._extend.Property({