github.com/MetalBlockchain/subnet-evm@v0.4.9/internal/ethapi/transaction_args.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2021 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package ethapi
    28  
    29  import (
    30  	"bytes"
    31  	"context"
    32  	"errors"
    33  	"fmt"
    34  	"math/big"
    35  
    36  	"github.com/MetalBlockchain/subnet-evm/core/types"
    37  	"github.com/MetalBlockchain/subnet-evm/params"
    38  	"github.com/MetalBlockchain/subnet-evm/rpc"
    39  	"github.com/ethereum/go-ethereum/common"
    40  	"github.com/ethereum/go-ethereum/common/hexutil"
    41  	"github.com/ethereum/go-ethereum/common/math"
    42  	"github.com/ethereum/go-ethereum/log"
    43  )
    44  
    45  // TransactionArgs represents the arguments to construct a new transaction
    46  // or a message call.
    47  type TransactionArgs struct {
    48  	From                 *common.Address `json:"from"`
    49  	To                   *common.Address `json:"to"`
    50  	Gas                  *hexutil.Uint64 `json:"gas"`
    51  	GasPrice             *hexutil.Big    `json:"gasPrice"`
    52  	MaxFeePerGas         *hexutil.Big    `json:"maxFeePerGas"`
    53  	MaxPriorityFeePerGas *hexutil.Big    `json:"maxPriorityFeePerGas"`
    54  	Value                *hexutil.Big    `json:"value"`
    55  	Nonce                *hexutil.Uint64 `json:"nonce"`
    56  
    57  	// We accept "data" and "input" for backwards-compatibility reasons.
    58  	// "input" is the newer name and should be preferred by clients.
    59  	// Issue detail: https://github.com/ethereum/go-ethereum/issues/15628
    60  	Data  *hexutil.Bytes `json:"data"`
    61  	Input *hexutil.Bytes `json:"input"`
    62  
    63  	// Introduced by AccessListTxType transaction.
    64  	AccessList *types.AccessList `json:"accessList,omitempty"`
    65  	ChainID    *hexutil.Big      `json:"chainId,omitempty"`
    66  }
    67  
    68  // from retrieves the transaction sender address.
    69  func (args *TransactionArgs) from() common.Address {
    70  	if args.From == nil {
    71  		return common.Address{}
    72  	}
    73  	return *args.From
    74  }
    75  
    76  // data retrieves the transaction calldata. Input field is preferred.
    77  func (args *TransactionArgs) data() []byte {
    78  	if args.Input != nil {
    79  		return *args.Input
    80  	}
    81  	if args.Data != nil {
    82  		return *args.Data
    83  	}
    84  	return nil
    85  }
    86  
    87  // setDefaults fills in default values for unspecified tx fields.
    88  func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
    89  	if err := args.setFeeDefaults(ctx, b); err != nil {
    90  		return err
    91  	}
    92  
    93  	if args.Value == nil {
    94  		args.Value = new(hexutil.Big)
    95  	}
    96  	if args.Nonce == nil {
    97  		nonce, err := b.GetPoolNonce(ctx, args.from())
    98  		if err != nil {
    99  			return err
   100  		}
   101  		args.Nonce = (*hexutil.Uint64)(&nonce)
   102  	}
   103  	if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
   104  		return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`)
   105  	}
   106  	if args.To == nil && len(args.data()) == 0 {
   107  		return errors.New(`contract creation without any data provided`)
   108  	}
   109  	// Estimate the gas usage if necessary.
   110  	if args.Gas == nil {
   111  		// These fields are immutable during the estimation, safe to
   112  		// pass the pointer directly.
   113  		data := args.data()
   114  		callArgs := TransactionArgs{
   115  			From:                 args.From,
   116  			To:                   args.To,
   117  			GasPrice:             args.GasPrice,
   118  			MaxFeePerGas:         args.MaxFeePerGas,
   119  			MaxPriorityFeePerGas: args.MaxPriorityFeePerGas,
   120  			Value:                args.Value,
   121  			Data:                 (*hexutil.Bytes)(&data),
   122  			AccessList:           args.AccessList,
   123  		}
   124  		pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
   125  		estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, b.RPCGasCap())
   126  		if err != nil {
   127  			return err
   128  		}
   129  		args.Gas = &estimated
   130  		log.Trace("Estimate gas usage automatically", "gas", args.Gas)
   131  	}
   132  	// If chain id is provided, ensure it matches the local chain id. Otherwise, set the local
   133  	// chain id as the default.
   134  	want := b.ChainConfig().ChainID
   135  	if args.ChainID != nil {
   136  		if have := (*big.Int)(args.ChainID); have.Cmp(want) != 0 {
   137  			return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, want)
   138  		}
   139  	} else {
   140  		args.ChainID = (*hexutil.Big)(want)
   141  	}
   142  	return nil
   143  }
   144  
   145  type feeBackend interface {
   146  	SuggestGasTipCap(ctx context.Context) (*big.Int, error)
   147  	CurrentHeader() *types.Header
   148  	ChainConfig() *params.ChainConfig
   149  }
   150  
   151  // setFeeDefaults fills in default fee values for unspecified tx fields.
   152  func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b feeBackend) error {
   153  	// If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error.
   154  	if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
   155  		return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
   156  	}
   157  	// If the tx has completely specified a fee mechanism, no default is needed. This allows users
   158  	// who are not yet synced past London to get defaults for other tx values. See
   159  	// https://github.com/ethereum/go-ethereum/pull/23274 for more information.
   160  	eip1559ParamsSet := args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil
   161  	if (args.GasPrice != nil && !eip1559ParamsSet) || (args.GasPrice == nil && eip1559ParamsSet) {
   162  		// Sanity check the EIP-1559 fee parameters if present.
   163  		if args.GasPrice == nil && args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
   164  			return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
   165  		}
   166  		return nil
   167  	}
   168  	// Now attempt to fill in default value depending on whether London is active or not.
   169  	head := b.CurrentHeader()
   170  	if b.ChainConfig().IsSubnetEVM(new(big.Int).SetUint64(head.Time)) {
   171  		// London is active, set maxPriorityFeePerGas and maxFeePerGas.
   172  		if err := args.setSubnetEVMFeeDefault(ctx, head, b); err != nil {
   173  			return err
   174  		}
   175  	} else {
   176  		if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil {
   177  			return errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active")
   178  		}
   179  		if args.GasPrice == nil {
   180  			price, err := b.SuggestGasTipCap(ctx)
   181  			if err != nil {
   182  				return err
   183  			}
   184  			args.GasPrice = (*hexutil.Big)(price)
   185  		}
   186  	}
   187  	return nil
   188  }
   189  
   190  // setSubnetEVMFeeDefault fills in reasonable default fee values for unspecified fields.
   191  func (args *TransactionArgs) setSubnetEVMFeeDefault(ctx context.Context, head *types.Header, b feeBackend) error {
   192  	// Set maxPriorityFeePerGas if it is missing.
   193  	if args.MaxPriorityFeePerGas == nil {
   194  		tip, err := b.SuggestGasTipCap(ctx)
   195  		if err != nil {
   196  			return err
   197  		}
   198  		args.MaxPriorityFeePerGas = (*hexutil.Big)(tip)
   199  	}
   200  	// Set maxFeePerGas if it is missing.
   201  	if args.MaxFeePerGas == nil {
   202  		// Set the max fee to be 2 times larger than the previous block's base fee.
   203  		// The additional slack allows the tx to not become invalidated if the base
   204  		// fee is rising.
   205  		gasFeeCap := new(big.Int).Add(
   206  			(*big.Int)(args.MaxPriorityFeePerGas),
   207  			new(big.Int).Mul(head.BaseFee, big.NewInt(2)),
   208  		)
   209  		args.MaxFeePerGas = (*hexutil.Big)(gasFeeCap)
   210  	}
   211  	// Both EIP-1559 fee parameters are now set; sanity check them.
   212  	if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
   213  		return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
   214  	}
   215  	return nil
   216  }
   217  
   218  // ToMessage converts the transaction arguments to the Message type used by the
   219  // core evm. This method is used in calls and traces that do not require a real
   220  // live transaction.
   221  func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (types.Message, error) {
   222  	// Reject invalid combinations of pre- and post-1559 fee styles
   223  	if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
   224  		return types.Message{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
   225  	}
   226  	// Set sender address or use zero address if none specified.
   227  	addr := args.from()
   228  
   229  	// Set default gas & gas price if none were set
   230  	gas := globalGasCap
   231  	if gas == 0 {
   232  		gas = uint64(math.MaxUint64 / 2)
   233  	}
   234  	if args.Gas != nil {
   235  		gas = uint64(*args.Gas)
   236  	}
   237  	if globalGasCap != 0 && globalGasCap < gas {
   238  		log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
   239  		gas = globalGasCap
   240  	}
   241  	var (
   242  		gasPrice  *big.Int
   243  		gasFeeCap *big.Int
   244  		gasTipCap *big.Int
   245  	)
   246  	if baseFee == nil {
   247  		// If there's no basefee, then it must be a non-1559 execution
   248  		gasPrice = new(big.Int)
   249  		if args.GasPrice != nil {
   250  			gasPrice = args.GasPrice.ToInt()
   251  		}
   252  		gasFeeCap, gasTipCap = gasPrice, gasPrice
   253  	} else {
   254  		// A basefee is provided, necessitating 1559-type execution
   255  		if args.GasPrice != nil {
   256  			// User specified the legacy gas field, convert to 1559 gas typing
   257  			gasPrice = args.GasPrice.ToInt()
   258  			gasFeeCap, gasTipCap = gasPrice, gasPrice
   259  		} else {
   260  			// User specified 1559 gas feilds (or none), use those
   261  			gasFeeCap = new(big.Int)
   262  			if args.MaxFeePerGas != nil {
   263  				gasFeeCap = args.MaxFeePerGas.ToInt()
   264  			}
   265  			gasTipCap = new(big.Int)
   266  			if args.MaxPriorityFeePerGas != nil {
   267  				gasTipCap = args.MaxPriorityFeePerGas.ToInt()
   268  			}
   269  			// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
   270  			gasPrice = new(big.Int)
   271  			if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 {
   272  				gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap)
   273  			}
   274  		}
   275  	}
   276  	value := new(big.Int)
   277  	if args.Value != nil {
   278  		value = args.Value.ToInt()
   279  	}
   280  	data := args.data()
   281  	var accessList types.AccessList
   282  	if args.AccessList != nil {
   283  		accessList = *args.AccessList
   284  	}
   285  	msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, true)
   286  	return msg, nil
   287  }
   288  
   289  // toTransaction converts the arguments to a transaction.
   290  // This assumes that setDefaults has been called.
   291  func (args *TransactionArgs) toTransaction() *types.Transaction {
   292  	var data types.TxData
   293  	switch {
   294  	case args.MaxFeePerGas != nil:
   295  		al := types.AccessList{}
   296  		if args.AccessList != nil {
   297  			al = *args.AccessList
   298  		}
   299  		data = &types.DynamicFeeTx{
   300  			To:         args.To,
   301  			ChainID:    (*big.Int)(args.ChainID),
   302  			Nonce:      uint64(*args.Nonce),
   303  			Gas:        uint64(*args.Gas),
   304  			GasFeeCap:  (*big.Int)(args.MaxFeePerGas),
   305  			GasTipCap:  (*big.Int)(args.MaxPriorityFeePerGas),
   306  			Value:      (*big.Int)(args.Value),
   307  			Data:       args.data(),
   308  			AccessList: al,
   309  		}
   310  	case args.AccessList != nil:
   311  		data = &types.AccessListTx{
   312  			To:         args.To,
   313  			ChainID:    (*big.Int)(args.ChainID),
   314  			Nonce:      uint64(*args.Nonce),
   315  			Gas:        uint64(*args.Gas),
   316  			GasPrice:   (*big.Int)(args.GasPrice),
   317  			Value:      (*big.Int)(args.Value),
   318  			Data:       args.data(),
   319  			AccessList: *args.AccessList,
   320  		}
   321  	default:
   322  		data = &types.LegacyTx{
   323  			To:       args.To,
   324  			Nonce:    uint64(*args.Nonce),
   325  			Gas:      uint64(*args.Gas),
   326  			GasPrice: (*big.Int)(args.GasPrice),
   327  			Value:    (*big.Int)(args.Value),
   328  			Data:     args.data(),
   329  		}
   330  	}
   331  	return types.NewTx(data)
   332  }
   333  
   334  // ToTransaction converts the arguments to a transaction.
   335  // This assumes that setDefaults has been called.
   336  func (args *TransactionArgs) ToTransaction() *types.Transaction {
   337  	return args.toTransaction()
   338  }