diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 1032d067f1..c4322fcbf8 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -42,6 +42,7 @@ import ( type TransactionArgs struct { From *common.Address `json:"from"` To *common.Address `json:"to"` + Type *hexutil.Uint64 `json:"type,omitempty"` Gas *hexutil.Uint64 `json:"gas"` GasPrice *hexutil.Big `json:"gasPrice"` MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` @@ -101,6 +102,9 @@ type sidecarConfig struct { // setDefaults fills in default values for unspecified tx fields. func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, config sidecarConfig) error { + if err := args.validateTxType(); err != nil { + return err + } if err := args.setBlobTxSidecar(ctx, config); err != nil { return err } @@ -390,6 +394,9 @@ func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context, config sideca // CallDefaults sanitizes the transaction arguments, often filling in zero values, // for the purpose of eth_call class of RPC methods. func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int, chainID *big.Int) error { + if err := args.validateTxType(); err != nil { + return err + } // Reject invalid combinations of pre- and post-1559 fee styles if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") @@ -440,6 +447,18 @@ func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int, return nil } +func (args *TransactionArgs) validateTxType() error { + if args.Type == nil { + return nil + } + switch uint64(*args.Type) { + case types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType: + return nil + default: + return fmt.Errorf("unsupported transaction type: %d", uint64(*args.Type)) + } +} + // ToMessage converts the transaction arguments to the Message type used by the // core evm. This method is used in calls and traces that do not require a real // live transaction. diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 30791f32b5..310fddcabb 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -256,6 +256,40 @@ func TestSetFeeDefaults(t *testing.T) { } } +func TestTransactionArgsRejectUnsupportedTypeInCallDefaults(t *testing.T) { + t.Parallel() + + badType := hexutil.Uint64(0x5) + args := &TransactionArgs{Type: &badType} + err := args.CallDefaults(0, big.NewInt(1), big.NewInt(1)) + if err == nil { + t.Fatal("expected error for unsupported transaction type") + } + if err.Error() != "unsupported transaction type: 5" { + t.Fatalf("unexpected error: %v", err) + } +} + +func TestTransactionArgsRejectUnsupportedTypeInSetDefaults(t *testing.T) { + t.Parallel() + + badType := hexutil.Uint64(0x5) + gas := hexutil.Uint64(21000) + to := common.Address{0x1} + args := &TransactionArgs{ + To: &to, + Gas: &gas, + Type: &badType, + } + err := args.setDefaults(context.Background(), newBackendMock(), sidecarConfig{}) + if err == nil { + t.Fatal("expected error for unsupported transaction type") + } + if err.Error() != "unsupported transaction type: 5" { + t.Fatalf("unexpected error: %v", err) + } +} + type backendMock struct { current *types.Header config *params.ChainConfig