github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/internal/ethapi/transaction_args.go (about)

     1  // Copyright 2021 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package ethapi
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"crypto/sha256"
    23  	"errors"
    24  	"fmt"
    25  	"math/big"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/common/hexutil"
    29  	"github.com/ethereum/go-ethereum/common/math"
    30  	"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
    31  	"github.com/ethereum/go-ethereum/core"
    32  	"github.com/ethereum/go-ethereum/core/types"
    33  	"github.com/ethereum/go-ethereum/crypto/kzg4844"
    34  	"github.com/ethereum/go-ethereum/log"
    35  	"github.com/ethereum/go-ethereum/params"
    36  	"github.com/ethereum/go-ethereum/rpc"
    37  	"github.com/holiman/uint256"
    38  )
    39  
    40  var (
    41  	maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob
    42  )
    43  
    44  // TransactionArgs represents the arguments to construct a new transaction
    45  // or a message call.
    46  type TransactionArgs struct {
    47  	From                 *common.Address `json:"from"`
    48  	To                   *common.Address `json:"to"`
    49  	Gas                  *hexutil.Uint64 `json:"gas"`
    50  	GasPrice             *hexutil.Big    `json:"gasPrice"`
    51  	MaxFeePerGas         *hexutil.Big    `json:"maxFeePerGas"`
    52  	MaxPriorityFeePerGas *hexutil.Big    `json:"maxPriorityFeePerGas"`
    53  	Value                *hexutil.Big    `json:"value"`
    54  	Nonce                *hexutil.Uint64 `json:"nonce"`
    55  
    56  	// We accept "data" and "input" for backwards-compatibility reasons.
    57  	// "input" is the newer name and should be preferred by clients.
    58  	// Issue detail: https://github.com/ethereum/go-ethereum/issues/15628
    59  	Data  *hexutil.Bytes `json:"data"`
    60  	Input *hexutil.Bytes `json:"input"`
    61  
    62  	// Introduced by AccessListTxType transaction.
    63  	AccessList *types.AccessList `json:"accessList,omitempty"`
    64  	ChainID    *hexutil.Big      `json:"chainId,omitempty"`
    65  
    66  	// For BlobTxType
    67  	BlobFeeCap *hexutil.Big  `json:"maxFeePerBlobGas"`
    68  	BlobHashes []common.Hash `json:"blobVersionedHashes,omitempty"`
    69  
    70  	// For BlobTxType transactions with blob sidecar
    71  	Blobs       []kzg4844.Blob       `json:"blobs"`
    72  	Commitments []kzg4844.Commitment `json:"commitments"`
    73  	Proofs      []kzg4844.Proof      `json:"proofs"`
    74  
    75  	// This configures whether blobs are allowed to be passed.
    76  	blobSidecarAllowed bool
    77  }
    78  
    79  // from retrieves the transaction sender address.
    80  func (args *TransactionArgs) from() common.Address {
    81  	if args.From == nil {
    82  		return common.Address{}
    83  	}
    84  	return *args.From
    85  }
    86  
    87  // data retrieves the transaction calldata. Input field is preferred.
    88  func (args *TransactionArgs) data() []byte {
    89  	if args.Input != nil {
    90  		return *args.Input
    91  	}
    92  	if args.Data != nil {
    93  		return *args.Data
    94  	}
    95  	return nil
    96  }
    97  
    98  // setDefaults fills in default values for unspecified tx fields.
    99  func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGasEstimation bool) error {
   100  	if err := args.setBlobTxSidecar(ctx); err != nil {
   101  		return err
   102  	}
   103  	if err := args.setFeeDefaults(ctx, b); err != nil {
   104  		return err
   105  	}
   106  
   107  	if args.Value == nil {
   108  		args.Value = new(hexutil.Big)
   109  	}
   110  	if args.Nonce == nil {
   111  		nonce, err := b.GetPoolNonce(ctx, args.from())
   112  		if err != nil {
   113  			return err
   114  		}
   115  		args.Nonce = (*hexutil.Uint64)(&nonce)
   116  	}
   117  	if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
   118  		return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`)
   119  	}
   120  
   121  	// BlobTx fields
   122  	if args.BlobHashes != nil && len(args.BlobHashes) == 0 {
   123  		return errors.New(`need at least 1 blob for a blob transaction`)
   124  	}
   125  	if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobsPerTransaction {
   126  		return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobsPerTransaction)
   127  	}
   128  
   129  	// create check
   130  	if args.To == nil {
   131  		if args.BlobHashes != nil {
   132  			return errors.New(`missing "to" in blob transaction`)
   133  		}
   134  		if len(args.data()) == 0 {
   135  			return errors.New(`contract creation without any data provided`)
   136  		}
   137  	}
   138  
   139  	if args.Gas == nil {
   140  		if skipGasEstimation { // Skip gas usage estimation if a precise gas limit is not critical, e.g., in non-transaction calls.
   141  			gas := hexutil.Uint64(b.RPCGasCap())
   142  			if gas == 0 {
   143  				gas = hexutil.Uint64(math.MaxUint64 / 2)
   144  			}
   145  			args.Gas = &gas
   146  		} else { // Estimate the gas usage otherwise.
   147  			// These fields are immutable during the estimation, safe to
   148  			// pass the pointer directly.
   149  			data := args.data()
   150  			callArgs := TransactionArgs{
   151  				From:                 args.From,
   152  				To:                   args.To,
   153  				GasPrice:             args.GasPrice,
   154  				MaxFeePerGas:         args.MaxFeePerGas,
   155  				MaxPriorityFeePerGas: args.MaxPriorityFeePerGas,
   156  				Value:                args.Value,
   157  				Data:                 (*hexutil.Bytes)(&data),
   158  				AccessList:           args.AccessList,
   159  				BlobFeeCap:           args.BlobFeeCap,
   160  				BlobHashes:           args.BlobHashes,
   161  			}
   162  			latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
   163  			estimated, err := DoEstimateGas(ctx, b, callArgs, latestBlockNr, nil, b.RPCGasCap())
   164  			if err != nil {
   165  				return err
   166  			}
   167  			args.Gas = &estimated
   168  			log.Trace("Estimate gas usage automatically", "gas", args.Gas)
   169  		}
   170  	}
   171  
   172  	// If chain id is provided, ensure it matches the local chain id. Otherwise, set the local
   173  	// chain id as the default.
   174  	want := b.ChainConfig().ChainID
   175  	if args.ChainID != nil {
   176  		if have := (*big.Int)(args.ChainID); have.Cmp(want) != 0 {
   177  			return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, want)
   178  		}
   179  	} else {
   180  		args.ChainID = (*hexutil.Big)(want)
   181  	}
   182  	return nil
   183  }
   184  
   185  // setFeeDefaults fills in default fee values for unspecified tx fields.
   186  func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) error {
   187  	head := b.CurrentHeader()
   188  	// Sanity check the EIP-4844 fee parameters.
   189  	if args.BlobFeeCap != nil && args.BlobFeeCap.ToInt().Sign() == 0 {
   190  		return errors.New("maxFeePerBlobGas, if specified, must be non-zero")
   191  	}
   192  	if err := args.setCancunFeeDefaults(ctx, head, b); err != nil {
   193  		return err
   194  	}
   195  	// If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error.
   196  	if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
   197  		return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
   198  	}
   199  	// If the tx has completely specified a fee mechanism, no default is needed.
   200  	// This allows users who are not yet synced past London to get defaults for
   201  	// other tx values. See https://github.com/ethereum/go-ethereum/pull/23274
   202  	// for more information.
   203  	eip1559ParamsSet := args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil
   204  	// Sanity check the EIP-1559 fee parameters if present.
   205  	if args.GasPrice == nil && eip1559ParamsSet {
   206  		if args.MaxFeePerGas.ToInt().Sign() == 0 {
   207  			return errors.New("maxFeePerGas must be non-zero")
   208  		}
   209  		if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
   210  			return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
   211  		}
   212  		return nil // No need to set anything, user already set MaxFeePerGas and MaxPriorityFeePerGas
   213  	}
   214  
   215  	// Sanity check the non-EIP-1559 fee parameters.
   216  	isLondon := b.ChainConfig().IsLondon(head.Number)
   217  	if args.GasPrice != nil && !eip1559ParamsSet {
   218  		// Zero gas-price is not allowed after London fork
   219  		if args.GasPrice.ToInt().Sign() == 0 && isLondon {
   220  			return errors.New("gasPrice must be non-zero after london fork")
   221  		}
   222  		return nil // No need to set anything, user already set GasPrice
   223  	}
   224  
   225  	// Now attempt to fill in default value depending on whether London is active or not.
   226  	if isLondon {
   227  		// London is active, set maxPriorityFeePerGas and maxFeePerGas.
   228  		if err := args.setLondonFeeDefaults(ctx, head, b); err != nil {
   229  			return err
   230  		}
   231  	} else {
   232  		if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil {
   233  			return errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active")
   234  		}
   235  		// London not active, set gas price.
   236  		price, err := b.SuggestGasTipCap(ctx)
   237  		if err != nil {
   238  			return err
   239  		}
   240  		args.GasPrice = (*hexutil.Big)(price)
   241  	}
   242  	return nil
   243  }
   244  
   245  // setCancunFeeDefaults fills in reasonable default fee values for unspecified fields.
   246  func (args *TransactionArgs) setCancunFeeDefaults(ctx context.Context, head *types.Header, b Backend) error {
   247  	// Set maxFeePerBlobGas if it is missing.
   248  	if args.BlobHashes != nil && args.BlobFeeCap == nil {
   249  		var excessBlobGas uint64
   250  		if head.ExcessBlobGas != nil {
   251  			excessBlobGas = *head.ExcessBlobGas
   252  		}
   253  		// ExcessBlobGas must be set for a Cancun block.
   254  		blobBaseFee := eip4844.CalcBlobFee(excessBlobGas)
   255  		// Set the max fee to be 2 times larger than the previous block's blob base fee.
   256  		// The additional slack allows the tx to not become invalidated if the base
   257  		// fee is rising.
   258  		val := new(big.Int).Mul(blobBaseFee, big.NewInt(2))
   259  		args.BlobFeeCap = (*hexutil.Big)(val)
   260  	}
   261  	return nil
   262  }
   263  
   264  // setLondonFeeDefaults fills in reasonable default fee values for unspecified fields.
   265  func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *types.Header, b Backend) error {
   266  	// Set maxPriorityFeePerGas if it is missing.
   267  	if args.MaxPriorityFeePerGas == nil {
   268  		tip, err := b.SuggestGasTipCap(ctx)
   269  		if err != nil {
   270  			return err
   271  		}
   272  		args.MaxPriorityFeePerGas = (*hexutil.Big)(tip)
   273  	}
   274  	// Set maxFeePerGas if it is missing.
   275  	if args.MaxFeePerGas == nil {
   276  		// Set the max fee to be 2 times larger than the previous block's base fee.
   277  		// The additional slack allows the tx to not become invalidated if the base
   278  		// fee is rising.
   279  		val := new(big.Int).Add(
   280  			args.MaxPriorityFeePerGas.ToInt(),
   281  			new(big.Int).Mul(head.BaseFee, big.NewInt(2)),
   282  		)
   283  		args.MaxFeePerGas = (*hexutil.Big)(val)
   284  	}
   285  	// Both EIP-1559 fee parameters are now set; sanity check them.
   286  	if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
   287  		return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
   288  	}
   289  	return nil
   290  }
   291  
   292  // setBlobTxSidecar adds the blob tx
   293  func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context) error {
   294  	// No blobs, we're done.
   295  	if args.Blobs == nil {
   296  		return nil
   297  	}
   298  
   299  	// Passing blobs is not allowed in all contexts, only in specific methods.
   300  	if !args.blobSidecarAllowed {
   301  		return errors.New(`"blobs" is not supported for this RPC method`)
   302  	}
   303  
   304  	n := len(args.Blobs)
   305  	// Assume user provides either only blobs (w/o hashes), or
   306  	// blobs together with commitments and proofs.
   307  	if args.Commitments == nil && args.Proofs != nil {
   308  		return errors.New(`blob proofs provided while commitments were not`)
   309  	} else if args.Commitments != nil && args.Proofs == nil {
   310  		return errors.New(`blob commitments provided while proofs were not`)
   311  	}
   312  
   313  	// len(blobs) == len(commitments) == len(proofs) == len(hashes)
   314  	if args.Commitments != nil && len(args.Commitments) != n {
   315  		return fmt.Errorf("number of blobs and commitments mismatch (have=%d, want=%d)", len(args.Commitments), n)
   316  	}
   317  	if args.Proofs != nil && len(args.Proofs) != n {
   318  		return fmt.Errorf("number of blobs and proofs mismatch (have=%d, want=%d)", len(args.Proofs), n)
   319  	}
   320  	if args.BlobHashes != nil && len(args.BlobHashes) != n {
   321  		return fmt.Errorf("number of blobs and hashes mismatch (have=%d, want=%d)", len(args.BlobHashes), n)
   322  	}
   323  
   324  	if args.Commitments == nil {
   325  		// Generate commitment and proof.
   326  		commitments := make([]kzg4844.Commitment, n)
   327  		proofs := make([]kzg4844.Proof, n)
   328  		for i, b := range args.Blobs {
   329  			c, err := kzg4844.BlobToCommitment(&b)
   330  			if err != nil {
   331  				return fmt.Errorf("blobs[%d]: error computing commitment: %v", i, err)
   332  			}
   333  			commitments[i] = c
   334  			p, err := kzg4844.ComputeBlobProof(&b, c)
   335  			if err != nil {
   336  				return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err)
   337  			}
   338  			proofs[i] = p
   339  		}
   340  		args.Commitments = commitments
   341  		args.Proofs = proofs
   342  	} else {
   343  		for i, b := range args.Blobs {
   344  			if err := kzg4844.VerifyBlobProof(&b, args.Commitments[i], args.Proofs[i]); err != nil {
   345  				return fmt.Errorf("failed to verify blob proof: %v", err)
   346  			}
   347  		}
   348  	}
   349  
   350  	hashes := make([]common.Hash, n)
   351  	hasher := sha256.New()
   352  	for i, c := range args.Commitments {
   353  		hashes[i] = kzg4844.CalcBlobHashV1(hasher, &c)
   354  	}
   355  	if args.BlobHashes != nil {
   356  		for i, h := range hashes {
   357  			if h != args.BlobHashes[i] {
   358  				return fmt.Errorf("blob hash verification failed (have=%s, want=%s)", args.BlobHashes[i], h)
   359  			}
   360  		}
   361  	} else {
   362  		args.BlobHashes = hashes
   363  	}
   364  	return nil
   365  }
   366  
   367  // CallDefaults sanitizes the transaction arguments, often filling in zero values,
   368  // for the purpose of eth_call class of RPC methods.
   369  func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int, chainID *big.Int) error {
   370  	// Reject invalid combinations of pre- and post-1559 fee styles
   371  	if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
   372  		return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
   373  	}
   374  	if args.ChainID == nil {
   375  		args.ChainID = (*hexutil.Big)(chainID)
   376  	} else {
   377  		if have := (*big.Int)(args.ChainID); have.Cmp(chainID) != 0 {
   378  			return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, chainID)
   379  		}
   380  	}
   381  	if args.Gas == nil {
   382  		gas := globalGasCap
   383  		if gas == 0 {
   384  			gas = uint64(math.MaxUint64 / 2)
   385  		}
   386  		args.Gas = (*hexutil.Uint64)(&gas)
   387  	} else {
   388  		if globalGasCap > 0 && globalGasCap < uint64(*args.Gas) {
   389  			log.Warn("Caller gas above allowance, capping", "requested", args.Gas, "cap", globalGasCap)
   390  			args.Gas = (*hexutil.Uint64)(&globalGasCap)
   391  		}
   392  	}
   393  	if args.Nonce == nil {
   394  		args.Nonce = new(hexutil.Uint64)
   395  	}
   396  	if args.Value == nil {
   397  		args.Value = new(hexutil.Big)
   398  	}
   399  	if baseFee == nil {
   400  		// If there's no basefee, then it must be a non-1559 execution
   401  		if args.GasPrice == nil {
   402  			args.GasPrice = new(hexutil.Big)
   403  		}
   404  	} else {
   405  		// A basefee is provided, necessitating 1559-type execution
   406  		if args.MaxFeePerGas == nil {
   407  			args.MaxFeePerGas = new(hexutil.Big)
   408  		}
   409  		if args.MaxPriorityFeePerGas == nil {
   410  			args.MaxPriorityFeePerGas = new(hexutil.Big)
   411  		}
   412  	}
   413  	if args.BlobFeeCap == nil && args.BlobHashes != nil {
   414  		args.BlobFeeCap = new(hexutil.Big)
   415  	}
   416  
   417  	return nil
   418  }
   419  
   420  // ToMessage converts the transaction arguments to the Message type used by the
   421  // core evm. This method is used in calls and traces that do not require a real
   422  // live transaction.
   423  // Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called.
   424  func (args *TransactionArgs) ToMessage(baseFee *big.Int) *core.Message {
   425  	var (
   426  		gasPrice  *big.Int
   427  		gasFeeCap *big.Int
   428  		gasTipCap *big.Int
   429  	)
   430  	if baseFee == nil {
   431  		gasPrice = args.GasPrice.ToInt()
   432  		gasFeeCap, gasTipCap = gasPrice, gasPrice
   433  	} else {
   434  		// A basefee is provided, necessitating 1559-type execution
   435  		if args.GasPrice != nil {
   436  			// User specified the legacy gas field, convert to 1559 gas typing
   437  			gasPrice = args.GasPrice.ToInt()
   438  			gasFeeCap, gasTipCap = gasPrice, gasPrice
   439  		} else {
   440  			// User specified 1559 gas fields (or none), use those
   441  			gasFeeCap = args.MaxFeePerGas.ToInt()
   442  			gasTipCap = args.MaxPriorityFeePerGas.ToInt()
   443  			// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
   444  			gasPrice = new(big.Int)
   445  			if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 {
   446  				gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap)
   447  			}
   448  		}
   449  	}
   450  	var accessList types.AccessList
   451  	if args.AccessList != nil {
   452  		accessList = *args.AccessList
   453  	}
   454  	return &core.Message{
   455  		From:              args.from(),
   456  		To:                args.To,
   457  		Value:             (*big.Int)(args.Value),
   458  		GasLimit:          uint64(*args.Gas),
   459  		GasPrice:          gasPrice,
   460  		GasFeeCap:         gasFeeCap,
   461  		GasTipCap:         gasTipCap,
   462  		Data:              args.data(),
   463  		AccessList:        accessList,
   464  		BlobGasFeeCap:     (*big.Int)(args.BlobFeeCap),
   465  		BlobHashes:        args.BlobHashes,
   466  		SkipAccountChecks: true,
   467  	}
   468  }
   469  
   470  // ToTransaction converts the arguments to a transaction.
   471  // This assumes that setDefaults has been called.
   472  func (args *TransactionArgs) ToTransaction() *types.Transaction {
   473  	var data types.TxData
   474  	switch {
   475  	case args.BlobHashes != nil:
   476  		al := types.AccessList{}
   477  		if args.AccessList != nil {
   478  			al = *args.AccessList
   479  		}
   480  		data = &types.BlobTx{
   481  			To:         *args.To,
   482  			ChainID:    uint256.MustFromBig((*big.Int)(args.ChainID)),
   483  			Nonce:      uint64(*args.Nonce),
   484  			Gas:        uint64(*args.Gas),
   485  			GasFeeCap:  uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)),
   486  			GasTipCap:  uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)),
   487  			Value:      uint256.MustFromBig((*big.Int)(args.Value)),
   488  			Data:       args.data(),
   489  			AccessList: al,
   490  			BlobHashes: args.BlobHashes,
   491  			BlobFeeCap: uint256.MustFromBig((*big.Int)(args.BlobFeeCap)),
   492  		}
   493  		if args.Blobs != nil {
   494  			data.(*types.BlobTx).Sidecar = &types.BlobTxSidecar{
   495  				Blobs:       args.Blobs,
   496  				Commitments: args.Commitments,
   497  				Proofs:      args.Proofs,
   498  			}
   499  		}
   500  
   501  	case args.MaxFeePerGas != nil:
   502  		al := types.AccessList{}
   503  		if args.AccessList != nil {
   504  			al = *args.AccessList
   505  		}
   506  		data = &types.DynamicFeeTx{
   507  			To:         args.To,
   508  			ChainID:    (*big.Int)(args.ChainID),
   509  			Nonce:      uint64(*args.Nonce),
   510  			Gas:        uint64(*args.Gas),
   511  			GasFeeCap:  (*big.Int)(args.MaxFeePerGas),
   512  			GasTipCap:  (*big.Int)(args.MaxPriorityFeePerGas),
   513  			Value:      (*big.Int)(args.Value),
   514  			Data:       args.data(),
   515  			AccessList: al,
   516  		}
   517  
   518  	case args.AccessList != nil:
   519  		data = &types.AccessListTx{
   520  			To:         args.To,
   521  			ChainID:    (*big.Int)(args.ChainID),
   522  			Nonce:      uint64(*args.Nonce),
   523  			Gas:        uint64(*args.Gas),
   524  			GasPrice:   (*big.Int)(args.GasPrice),
   525  			Value:      (*big.Int)(args.Value),
   526  			Data:       args.data(),
   527  			AccessList: *args.AccessList,
   528  		}
   529  
   530  	default:
   531  		data = &types.LegacyTx{
   532  			To:       args.To,
   533  			Nonce:    uint64(*args.Nonce),
   534  			Gas:      uint64(*args.Gas),
   535  			GasPrice: (*big.Int)(args.GasPrice),
   536  			Value:    (*big.Int)(args.Value),
   537  			Data:     args.data(),
   538  		}
   539  	}
   540  	return types.NewTx(data)
   541  }
   542  
   543  // IsEIP4844 returns an indicator if the args contains EIP4844 fields.
   544  func (args *TransactionArgs) IsEIP4844() bool {
   545  	return args.BlobHashes != nil || args.BlobFeeCap != nil
   546  }