github.com/ethereum/go-ethereum@v1.16.1/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"
    26  	"math/big"
    27  
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/common/hexutil"
    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  // TransactionArgs represents the arguments to construct a new transaction
    41  // or a message call.
    42  type TransactionArgs struct {
    43  	From                 *common.Address `json:"from"`
    44  	To                   *common.Address `json:"to"`
    45  	Gas                  *hexutil.Uint64 `json:"gas"`
    46  	GasPrice             *hexutil.Big    `json:"gasPrice"`
    47  	MaxFeePerGas         *hexutil.Big    `json:"maxFeePerGas"`
    48  	MaxPriorityFeePerGas *hexutil.Big    `json:"maxPriorityFeePerGas"`
    49  	Value                *hexutil.Big    `json:"value"`
    50  	Nonce                *hexutil.Uint64 `json:"nonce"`
    51  
    52  	// We accept "data" and "input" for backwards-compatibility reasons.
    53  	// "input" is the newer name and should be preferred by clients.
    54  	// Issue detail: https://github.com/ethereum/go-ethereum/issues/15628
    55  	Data  *hexutil.Bytes `json:"data"`
    56  	Input *hexutil.Bytes `json:"input"`
    57  
    58  	// Introduced by AccessListTxType transaction.
    59  	AccessList *types.AccessList `json:"accessList,omitempty"`
    60  	ChainID    *hexutil.Big      `json:"chainId,omitempty"`
    61  
    62  	// For BlobTxType
    63  	BlobFeeCap *hexutil.Big  `json:"maxFeePerBlobGas"`
    64  	BlobHashes []common.Hash `json:"blobVersionedHashes,omitempty"`
    65  
    66  	// For BlobTxType transactions with blob sidecar
    67  	Blobs       []kzg4844.Blob       `json:"blobs"`
    68  	Commitments []kzg4844.Commitment `json:"commitments"`
    69  	Proofs      []kzg4844.Proof      `json:"proofs"`
    70  
    71  	// For SetCodeTxType
    72  	AuthorizationList []types.SetCodeAuthorization `json:"authorizationList"`
    73  
    74  	// This configures whether blobs are allowed to be passed.
    75  	blobSidecarAllowed bool
    76  }
    77  
    78  // from retrieves the transaction sender address.
    79  func (args *TransactionArgs) from() common.Address {
    80  	if args.From == nil {
    81  		return common.Address{}
    82  	}
    83  	return *args.From
    84  }
    85  
    86  // data retrieves the transaction calldata. Input field is preferred.
    87  func (args *TransactionArgs) data() []byte {
    88  	if args.Input != nil {
    89  		return *args.Input
    90  	}
    91  	if args.Data != nil {
    92  		return *args.Data
    93  	}
    94  	return nil
    95  }
    96  
    97  // setDefaults fills in default values for unspecified tx fields.
    98  func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGasEstimation bool) error {
    99  	if err := args.setBlobTxSidecar(ctx); err != nil {
   100  		return err
   101  	}
   102  	if err := args.setFeeDefaults(ctx, b, b.CurrentHeader()); err != nil {
   103  		return err
   104  	}
   105  
   106  	if args.Value == nil {
   107  		args.Value = new(hexutil.Big)
   108  	}
   109  	if args.Nonce == nil {
   110  		nonce, err := b.GetPoolNonce(ctx, args.from())
   111  		if err != nil {
   112  			return err
   113  		}
   114  		args.Nonce = (*hexutil.Uint64)(&nonce)
   115  	}
   116  	if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
   117  		return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`)
   118  	}
   119  
   120  	// BlobTx fields
   121  	if args.BlobHashes != nil && len(args.BlobHashes) == 0 {
   122  		return errors.New(`need at least 1 blob for a blob transaction`)
   123  	}
   124  	maxBlobs := eip4844.MaxBlobsPerBlock(b.ChainConfig(), b.CurrentHeader().Time)
   125  	if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobs {
   126  		return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobs)
   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, 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, head *types.Header) error {
   187  	// Sanity check the EIP-4844 fee parameters.
   188  	if args.BlobFeeCap != nil && args.BlobFeeCap.ToInt().Sign() == 0 {
   189  		return errors.New("maxFeePerBlobGas, if specified, must be non-zero")
   190  	}
   191  	if b.ChainConfig().IsCancun(head.Number, head.Time) {
   192  		args.setCancunFeeDefaults(b.ChainConfig(), head)
   193  	}
   194  	// If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error.
   195  	if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
   196  		return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
   197  	}
   198  	// If the tx has completely specified a fee mechanism, no default is needed.
   199  	// This allows users who are not yet synced past London to get defaults for
   200  	// other tx values. See https://github.com/ethereum/go-ethereum/pull/23274
   201  	// for more information.
   202  	eip1559ParamsSet := args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil
   203  	// Sanity check the EIP-1559 fee parameters if present.
   204  	if args.GasPrice == nil && eip1559ParamsSet {
   205  		if args.MaxFeePerGas.ToInt().Sign() == 0 {
   206  			return errors.New("maxFeePerGas must be non-zero")
   207  		}
   208  		if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
   209  			return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
   210  		}
   211  		return nil // No need to set anything, user already set MaxFeePerGas and MaxPriorityFeePerGas
   212  	}
   213  
   214  	// Sanity check the non-EIP-1559 fee parameters.
   215  	isLondon := b.ChainConfig().IsLondon(head.Number)
   216  	if args.GasPrice != nil && !eip1559ParamsSet {
   217  		// Zero gas-price is not allowed after London fork
   218  		if args.GasPrice.ToInt().Sign() == 0 && isLondon {
   219  			return errors.New("gasPrice must be non-zero after london fork")
   220  		}
   221  		return nil // No need to set anything, user already set GasPrice
   222  	}
   223  
   224  	// Now attempt to fill in default value depending on whether London is active or not.
   225  	if isLondon {
   226  		// London is active, set maxPriorityFeePerGas and maxFeePerGas.
   227  		if err := args.setLondonFeeDefaults(ctx, head, b); err != nil {
   228  			return err
   229  		}
   230  	} else {
   231  		if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil {
   232  			return errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active")
   233  		}
   234  		// London not active, set gas price.
   235  		price, err := b.SuggestGasTipCap(ctx)
   236  		if err != nil {
   237  			return err
   238  		}
   239  		args.GasPrice = (*hexutil.Big)(price)
   240  	}
   241  	return nil
   242  }
   243  
   244  // setCancunFeeDefaults fills in reasonable default fee values for unspecified fields.
   245  func (args *TransactionArgs) setCancunFeeDefaults(config *params.ChainConfig, head *types.Header) {
   246  	// Set maxFeePerBlobGas if it is missing.
   247  	if args.BlobHashes != nil && args.BlobFeeCap == nil {
   248  		blobBaseFee := eip4844.CalcBlobFee(config, head)
   249  		// Set the max fee to be 2 times larger than the previous block's blob base fee.
   250  		// The additional slack allows the tx to not become invalidated if the base
   251  		// fee is rising.
   252  		val := new(big.Int).Mul(blobBaseFee, big.NewInt(2))
   253  		args.BlobFeeCap = (*hexutil.Big)(val)
   254  	}
   255  }
   256  
   257  // setLondonFeeDefaults fills in reasonable default fee values for unspecified fields.
   258  func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *types.Header, b Backend) error {
   259  	// Set maxPriorityFeePerGas if it is missing.
   260  	if args.MaxPriorityFeePerGas == nil {
   261  		tip, err := b.SuggestGasTipCap(ctx)
   262  		if err != nil {
   263  			return err
   264  		}
   265  		args.MaxPriorityFeePerGas = (*hexutil.Big)(tip)
   266  	}
   267  	// Set maxFeePerGas if it is missing.
   268  	if args.MaxFeePerGas == nil {
   269  		// Set the max fee to be 2 times larger than the previous block's base fee.
   270  		// The additional slack allows the tx to not become invalidated if the base
   271  		// fee is rising.
   272  		val := new(big.Int).Add(
   273  			args.MaxPriorityFeePerGas.ToInt(),
   274  			new(big.Int).Mul(head.BaseFee, big.NewInt(2)),
   275  		)
   276  		args.MaxFeePerGas = (*hexutil.Big)(val)
   277  	}
   278  	// Both EIP-1559 fee parameters are now set; sanity check them.
   279  	if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
   280  		return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
   281  	}
   282  	return nil
   283  }
   284  
   285  // setBlobTxSidecar adds the blob tx
   286  func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context) error {
   287  	// No blobs, we're done.
   288  	if args.Blobs == nil {
   289  		return nil
   290  	}
   291  
   292  	// Passing blobs is not allowed in all contexts, only in specific methods.
   293  	if !args.blobSidecarAllowed {
   294  		return errors.New(`"blobs" is not supported for this RPC method`)
   295  	}
   296  
   297  	n := len(args.Blobs)
   298  	// Assume user provides either only blobs (w/o hashes), or
   299  	// blobs together with commitments and proofs.
   300  	if args.Commitments == nil && args.Proofs != nil {
   301  		return errors.New(`blob proofs provided while commitments were not`)
   302  	} else if args.Commitments != nil && args.Proofs == nil {
   303  		return errors.New(`blob commitments provided while proofs were not`)
   304  	}
   305  
   306  	// len(blobs) == len(commitments) == len(proofs) == len(hashes)
   307  	if args.Commitments != nil && len(args.Commitments) != n {
   308  		return fmt.Errorf("number of blobs and commitments mismatch (have=%d, want=%d)", len(args.Commitments), n)
   309  	}
   310  	if args.Proofs != nil && len(args.Proofs) != n {
   311  		return fmt.Errorf("number of blobs and proofs mismatch (have=%d, want=%d)", len(args.Proofs), n)
   312  	}
   313  	if args.BlobHashes != nil && len(args.BlobHashes) != n {
   314  		return fmt.Errorf("number of blobs and hashes mismatch (have=%d, want=%d)", len(args.BlobHashes), n)
   315  	}
   316  
   317  	if args.Commitments == nil {
   318  		// Generate commitment and proof.
   319  		commitments := make([]kzg4844.Commitment, n)
   320  		proofs := make([]kzg4844.Proof, n)
   321  		for i, b := range args.Blobs {
   322  			c, err := kzg4844.BlobToCommitment(&b)
   323  			if err != nil {
   324  				return fmt.Errorf("blobs[%d]: error computing commitment: %v", i, err)
   325  			}
   326  			commitments[i] = c
   327  			p, err := kzg4844.ComputeBlobProof(&b, c)
   328  			if err != nil {
   329  				return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err)
   330  			}
   331  			proofs[i] = p
   332  		}
   333  		args.Commitments = commitments
   334  		args.Proofs = proofs
   335  	} else {
   336  		for i, b := range args.Blobs {
   337  			if err := kzg4844.VerifyBlobProof(&b, args.Commitments[i], args.Proofs[i]); err != nil {
   338  				return fmt.Errorf("failed to verify blob proof: %v", err)
   339  			}
   340  		}
   341  	}
   342  
   343  	hashes := make([]common.Hash, n)
   344  	hasher := sha256.New()
   345  	for i, c := range args.Commitments {
   346  		hashes[i] = kzg4844.CalcBlobHashV1(hasher, &c)
   347  	}
   348  	if args.BlobHashes != nil {
   349  		for i, h := range hashes {
   350  			if h != args.BlobHashes[i] {
   351  				return fmt.Errorf("blob hash verification failed (have=%s, want=%s)", args.BlobHashes[i], h)
   352  			}
   353  		}
   354  	} else {
   355  		args.BlobHashes = hashes
   356  	}
   357  	return nil
   358  }
   359  
   360  // CallDefaults sanitizes the transaction arguments, often filling in zero values,
   361  // for the purpose of eth_call class of RPC methods.
   362  func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int, chainID *big.Int) error {
   363  	// Reject invalid combinations of pre- and post-1559 fee styles
   364  	if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
   365  		return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
   366  	}
   367  	if args.ChainID == nil {
   368  		args.ChainID = (*hexutil.Big)(chainID)
   369  	} else {
   370  		if have := (*big.Int)(args.ChainID); have.Cmp(chainID) != 0 {
   371  			return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, chainID)
   372  		}
   373  	}
   374  	if args.Gas == nil {
   375  		gas := globalGasCap
   376  		if gas == 0 {
   377  			gas = uint64(math.MaxUint64 / 2)
   378  		}
   379  		args.Gas = (*hexutil.Uint64)(&gas)
   380  	} else {
   381  		if globalGasCap > 0 && globalGasCap < uint64(*args.Gas) {
   382  			log.Warn("Caller gas above allowance, capping", "requested", args.Gas, "cap", globalGasCap)
   383  			args.Gas = (*hexutil.Uint64)(&globalGasCap)
   384  		}
   385  	}
   386  	if args.Nonce == nil {
   387  		args.Nonce = new(hexutil.Uint64)
   388  	}
   389  	if args.Value == nil {
   390  		args.Value = new(hexutil.Big)
   391  	}
   392  	if baseFee == nil {
   393  		// If there's no basefee, then it must be a non-1559 execution
   394  		if args.GasPrice == nil {
   395  			args.GasPrice = new(hexutil.Big)
   396  		}
   397  	} else {
   398  		// A basefee is provided, necessitating 1559-type execution
   399  		if args.MaxFeePerGas == nil {
   400  			args.MaxFeePerGas = new(hexutil.Big)
   401  		}
   402  		if args.MaxPriorityFeePerGas == nil {
   403  			args.MaxPriorityFeePerGas = new(hexutil.Big)
   404  		}
   405  	}
   406  	if args.BlobFeeCap == nil && args.BlobHashes != nil {
   407  		args.BlobFeeCap = new(hexutil.Big)
   408  	}
   409  
   410  	return nil
   411  }
   412  
   413  // ToMessage converts the transaction arguments to the Message type used by the
   414  // core evm. This method is used in calls and traces that do not require a real
   415  // live transaction.
   416  // Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called.
   417  func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoACheck bool) *core.Message {
   418  	var (
   419  		gasPrice  *big.Int
   420  		gasFeeCap *big.Int
   421  		gasTipCap *big.Int
   422  	)
   423  	if baseFee == nil {
   424  		gasPrice = args.GasPrice.ToInt()
   425  		gasFeeCap, gasTipCap = gasPrice, gasPrice
   426  	} else {
   427  		// A basefee is provided, necessitating 1559-type execution
   428  		if args.GasPrice != nil {
   429  			// User specified the legacy gas field, convert to 1559 gas typing
   430  			gasPrice = args.GasPrice.ToInt()
   431  			gasFeeCap, gasTipCap = gasPrice, gasPrice
   432  		} else {
   433  			// User specified 1559 gas fields (or none), use those
   434  			gasFeeCap = args.MaxFeePerGas.ToInt()
   435  			gasTipCap = args.MaxPriorityFeePerGas.ToInt()
   436  			// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
   437  			gasPrice = new(big.Int)
   438  			if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 {
   439  				gasPrice = gasPrice.Add(gasTipCap, baseFee)
   440  				if gasPrice.Cmp(gasFeeCap) > 0 {
   441  					gasPrice = gasFeeCap
   442  				}
   443  			}
   444  		}
   445  	}
   446  	var accessList types.AccessList
   447  	if args.AccessList != nil {
   448  		accessList = *args.AccessList
   449  	}
   450  	return &core.Message{
   451  		From:                  args.from(),
   452  		To:                    args.To,
   453  		Value:                 (*big.Int)(args.Value),
   454  		Nonce:                 uint64(*args.Nonce),
   455  		GasLimit:              uint64(*args.Gas),
   456  		GasPrice:              gasPrice,
   457  		GasFeeCap:             gasFeeCap,
   458  		GasTipCap:             gasTipCap,
   459  		Data:                  args.data(),
   460  		AccessList:            accessList,
   461  		BlobGasFeeCap:         (*big.Int)(args.BlobFeeCap),
   462  		BlobHashes:            args.BlobHashes,
   463  		SetCodeAuthorizations: args.AuthorizationList,
   464  		SkipNonceChecks:       skipNonceCheck,
   465  		SkipFromEOACheck:      skipEoACheck,
   466  	}
   467  }
   468  
   469  // ToTransaction converts the arguments to a transaction.
   470  // This assumes that setDefaults has been called.
   471  func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction {
   472  	usedType := types.LegacyTxType
   473  	switch {
   474  	case args.AuthorizationList != nil || defaultType == types.SetCodeTxType:
   475  		usedType = types.SetCodeTxType
   476  	case args.BlobHashes != nil || defaultType == types.BlobTxType:
   477  		usedType = types.BlobTxType
   478  	case args.MaxFeePerGas != nil || defaultType == types.DynamicFeeTxType:
   479  		usedType = types.DynamicFeeTxType
   480  	case args.AccessList != nil || defaultType == types.AccessListTxType:
   481  		usedType = types.AccessListTxType
   482  	}
   483  	// Make it possible to default to newer tx, but use legacy if gasprice is provided
   484  	if args.GasPrice != nil {
   485  		usedType = types.LegacyTxType
   486  	}
   487  	var data types.TxData
   488  	switch usedType {
   489  	case types.SetCodeTxType:
   490  		al := types.AccessList{}
   491  		if args.AccessList != nil {
   492  			al = *args.AccessList
   493  		}
   494  		authList := []types.SetCodeAuthorization{}
   495  		if args.AuthorizationList != nil {
   496  			authList = args.AuthorizationList
   497  		}
   498  		data = &types.SetCodeTx{
   499  			To:         *args.To,
   500  			ChainID:    uint256.MustFromBig(args.ChainID.ToInt()),
   501  			Nonce:      uint64(*args.Nonce),
   502  			Gas:        uint64(*args.Gas),
   503  			GasFeeCap:  uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)),
   504  			GasTipCap:  uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)),
   505  			Value:      uint256.MustFromBig((*big.Int)(args.Value)),
   506  			Data:       args.data(),
   507  			AccessList: al,
   508  			AuthList:   authList,
   509  		}
   510  
   511  	case types.BlobTxType:
   512  		al := types.AccessList{}
   513  		if args.AccessList != nil {
   514  			al = *args.AccessList
   515  		}
   516  		data = &types.BlobTx{
   517  			To:         *args.To,
   518  			ChainID:    uint256.MustFromBig((*big.Int)(args.ChainID)),
   519  			Nonce:      uint64(*args.Nonce),
   520  			Gas:        uint64(*args.Gas),
   521  			GasFeeCap:  uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)),
   522  			GasTipCap:  uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)),
   523  			Value:      uint256.MustFromBig((*big.Int)(args.Value)),
   524  			Data:       args.data(),
   525  			AccessList: al,
   526  			BlobHashes: args.BlobHashes,
   527  			BlobFeeCap: uint256.MustFromBig((*big.Int)(args.BlobFeeCap)),
   528  		}
   529  		if args.Blobs != nil {
   530  			data.(*types.BlobTx).Sidecar = &types.BlobTxSidecar{
   531  				Blobs:       args.Blobs,
   532  				Commitments: args.Commitments,
   533  				Proofs:      args.Proofs,
   534  			}
   535  		}
   536  
   537  	case types.DynamicFeeTxType:
   538  		al := types.AccessList{}
   539  		if args.AccessList != nil {
   540  			al = *args.AccessList
   541  		}
   542  		data = &types.DynamicFeeTx{
   543  			To:         args.To,
   544  			ChainID:    (*big.Int)(args.ChainID),
   545  			Nonce:      uint64(*args.Nonce),
   546  			Gas:        uint64(*args.Gas),
   547  			GasFeeCap:  (*big.Int)(args.MaxFeePerGas),
   548  			GasTipCap:  (*big.Int)(args.MaxPriorityFeePerGas),
   549  			Value:      (*big.Int)(args.Value),
   550  			Data:       args.data(),
   551  			AccessList: al,
   552  		}
   553  
   554  	case types.AccessListTxType:
   555  		data = &types.AccessListTx{
   556  			To:         args.To,
   557  			ChainID:    (*big.Int)(args.ChainID),
   558  			Nonce:      uint64(*args.Nonce),
   559  			Gas:        uint64(*args.Gas),
   560  			GasPrice:   (*big.Int)(args.GasPrice),
   561  			Value:      (*big.Int)(args.Value),
   562  			Data:       args.data(),
   563  			AccessList: *args.AccessList,
   564  		}
   565  
   566  	default:
   567  		data = &types.LegacyTx{
   568  			To:       args.To,
   569  			Nonce:    uint64(*args.Nonce),
   570  			Gas:      uint64(*args.Gas),
   571  			GasPrice: (*big.Int)(args.GasPrice),
   572  			Value:    (*big.Int)(args.Value),
   573  			Data:     args.data(),
   574  		}
   575  	}
   576  	return types.NewTx(data)
   577  }
   578  
   579  // IsEIP4844 returns an indicator if the args contains EIP4844 fields.
   580  func (args *TransactionArgs) IsEIP4844() bool {
   581  	return args.BlobHashes != nil || args.BlobFeeCap != nil
   582  }