|
|
@@ -743,7 +743,21 @@ type CallArgs struct {
|
|
|
Data *hexutil.Bytes `json:"data"`
|
|
|
}
|
|
|
|
|
|
-func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration, globalGasCap *big.Int) ([]byte, uint64, bool, error) {
|
|
|
+// account indicates the overriding fields of account during the execution of
|
|
|
+// a message call.
|
|
|
+// Note, state and stateDiff can't be specified at the same time. If state is
|
|
|
+// set, message execution will only use the data in the given state. Otherwise
|
|
|
+// if statDiff is set, all diff will be applied first and then execute the call
|
|
|
+// message.
|
|
|
+type account struct {
|
|
|
+ Nonce *hexutil.Uint64 `json:"nonce"`
|
|
|
+ Code *hexutil.Bytes `json:"code"`
|
|
|
+ Balance **hexutil.Big `json:"balance"`
|
|
|
+ State *map[common.Hash]common.Hash `json:"state"`
|
|
|
+ StateDiff *map[common.Hash]common.Hash `json:"stateDiff"`
|
|
|
+}
|
|
|
+
|
|
|
+func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber, overrides map[common.Address]account, vmCfg vm.Config, timeout time.Duration, globalGasCap *big.Int) ([]byte, uint64, bool, error) {
|
|
|
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
|
|
|
|
|
state, header, err := b.StateAndHeaderByNumber(ctx, blockNr)
|
|
|
@@ -761,6 +775,34 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb
|
|
|
} else {
|
|
|
addr = *args.From
|
|
|
}
|
|
|
+ // Override the fields of specified contracts before execution.
|
|
|
+ for addr, account := range overrides {
|
|
|
+ // Override account nonce.
|
|
|
+ if account.Nonce != nil {
|
|
|
+ state.SetNonce(addr, uint64(*account.Nonce))
|
|
|
+ }
|
|
|
+ // Override account(contract) code.
|
|
|
+ if account.Code != nil {
|
|
|
+ state.SetCode(addr, *account.Code)
|
|
|
+ }
|
|
|
+ // Override account balance.
|
|
|
+ if account.Balance != nil {
|
|
|
+ state.SetBalance(addr, (*big.Int)(*account.Balance))
|
|
|
+ }
|
|
|
+ if account.State != nil && account.StateDiff != nil {
|
|
|
+ return nil, 0, false, fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
|
|
|
+ }
|
|
|
+ // Replace entire state if caller requires.
|
|
|
+ if account.State != nil {
|
|
|
+ state.SetStorage(addr, *account.State)
|
|
|
+ }
|
|
|
+ // Apply state diff into specified accounts.
|
|
|
+ if account.StateDiff != nil {
|
|
|
+ for key, value := range *account.StateDiff {
|
|
|
+ state.SetState(addr, key, value)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
// Set default gas & gas price if none were set
|
|
|
gas := uint64(math.MaxUint64 / 2)
|
|
|
if args.Gas != nil {
|
|
|
@@ -827,9 +869,17 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb
|
|
|
}
|
|
|
|
|
|
// 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 := DoCall(ctx, s.b, args, blockNr, vm.Config{}, 5*time.Second, s.b.RPCGasCap())
|
|
|
+//
|
|
|
+// Additionally, the caller can specify a batch of contract for fields overriding.
|
|
|
+//
|
|
|
+// Note, this function 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, overrides *map[common.Address]account) (hexutil.Bytes, error) {
|
|
|
+ var accounts map[common.Address]account
|
|
|
+ if overrides != nil {
|
|
|
+ accounts = *overrides
|
|
|
+ }
|
|
|
+ result, _, _, err := DoCall(ctx, s.b, args, blockNr, accounts, vm.Config{}, 5*time.Second, s.b.RPCGasCap())
|
|
|
return (hexutil.Bytes)(result), err
|
|
|
}
|
|
|
|
|
|
@@ -860,7 +910,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
|
|
|
executable := func(gas uint64) bool {
|
|
|
args.Gas = (*hexutil.Uint64)(&gas)
|
|
|
|
|
|
- _, _, failed, err := DoCall(ctx, b, args, rpc.PendingBlockNumber, vm.Config{}, 0, gasCap)
|
|
|
+ _, _, failed, err := DoCall(ctx, b, args, rpc.PendingBlockNumber, nil, vm.Config{}, 0, gasCap)
|
|
|
if err != nil || failed {
|
|
|
return false
|
|
|
}
|