github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/tx/decoder.go (about)

     1  package tx
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"google.golang.org/protobuf/encoding/protowire"
     7  
     8  	errorsmod "cosmossdk.io/errors"
     9  
    10  	"github.com/cosmos/cosmos-sdk/codec"
    11  	"github.com/cosmos/cosmos-sdk/codec/unknownproto"
    12  	sdk "github.com/cosmos/cosmos-sdk/types"
    13  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    14  	"github.com/cosmos/cosmos-sdk/types/tx"
    15  )
    16  
    17  // DefaultTxDecoder returns a default protobuf TxDecoder using the provided Marshaler.
    18  func DefaultTxDecoder(cdc codec.Codec) sdk.TxDecoder {
    19  	return func(txBytes []byte) (sdk.Tx, error) {
    20  		// Make sure txBytes follow ADR-027.
    21  		err := rejectNonADR027TxRaw(txBytes)
    22  		if err != nil {
    23  			return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, err.Error())
    24  		}
    25  
    26  		var raw tx.TxRaw
    27  
    28  		// reject all unknown proto fields in the root TxRaw
    29  		err = unknownproto.RejectUnknownFieldsStrict(txBytes, &raw, cdc.InterfaceRegistry())
    30  		if err != nil {
    31  			return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, err.Error())
    32  		}
    33  
    34  		err = cdc.Unmarshal(txBytes, &raw)
    35  		if err != nil {
    36  			return nil, err
    37  		}
    38  
    39  		var body tx.TxBody
    40  
    41  		// allow non-critical unknown fields in TxBody
    42  		txBodyHasUnknownNonCriticals, err := unknownproto.RejectUnknownFields(raw.BodyBytes, &body, true, cdc.InterfaceRegistry())
    43  		if err != nil {
    44  			return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, err.Error())
    45  		}
    46  
    47  		err = cdc.Unmarshal(raw.BodyBytes, &body)
    48  		if err != nil {
    49  			return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, err.Error())
    50  		}
    51  
    52  		var authInfo tx.AuthInfo
    53  
    54  		// reject all unknown proto fields in AuthInfo
    55  		err = unknownproto.RejectUnknownFieldsStrict(raw.AuthInfoBytes, &authInfo, cdc.InterfaceRegistry())
    56  		if err != nil {
    57  			return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, err.Error())
    58  		}
    59  
    60  		err = cdc.Unmarshal(raw.AuthInfoBytes, &authInfo)
    61  		if err != nil {
    62  			return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, err.Error())
    63  		}
    64  
    65  		theTx := &tx.Tx{
    66  			Body:       &body,
    67  			AuthInfo:   &authInfo,
    68  			Signatures: raw.Signatures,
    69  		}
    70  
    71  		return &wrapper{
    72  			tx:                           theTx,
    73  			bodyBz:                       raw.BodyBytes,
    74  			authInfoBz:                   raw.AuthInfoBytes,
    75  			txBodyHasUnknownNonCriticals: txBodyHasUnknownNonCriticals,
    76  			cdc:                          cdc,
    77  		}, nil
    78  	}
    79  }
    80  
    81  // DefaultJSONTxDecoder returns a default protobuf JSON TxDecoder using the provided Marshaler.
    82  func DefaultJSONTxDecoder(cdc codec.Codec) sdk.TxDecoder {
    83  	return func(txBytes []byte) (sdk.Tx, error) {
    84  		var theTx tx.Tx
    85  		err := cdc.UnmarshalJSON(txBytes, &theTx)
    86  		if err != nil {
    87  			return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, err.Error())
    88  		}
    89  
    90  		return &wrapper{
    91  			tx:  &theTx,
    92  			cdc: cdc,
    93  		}, nil
    94  	}
    95  }
    96  
    97  // rejectNonADR027TxRaw rejects txBytes that do not follow ADR-027. This is NOT
    98  // a generic ADR-027 checker, it only applies decoding TxRaw. Specifically, it
    99  // only checks that:
   100  // - field numbers are in ascending order (1, 2, and potentially multiple 3s),
   101  // - and varints are as short as possible.
   102  // All other ADR-027 edge cases (e.g. default values) are not applicable with
   103  // TxRaw.
   104  func rejectNonADR027TxRaw(txBytes []byte) error {
   105  	// Make sure all fields are ordered in ascending order with this variable.
   106  	prevTagNum := protowire.Number(0)
   107  
   108  	for len(txBytes) > 0 {
   109  		tagNum, wireType, m := protowire.ConsumeTag(txBytes)
   110  		if m < 0 {
   111  			return fmt.Errorf("invalid length; %w", protowire.ParseError(m))
   112  		}
   113  		// TxRaw only has bytes fields.
   114  		if wireType != protowire.BytesType {
   115  			return fmt.Errorf("expected %d wire type, got %d", protowire.BytesType, wireType)
   116  		}
   117  		// Make sure fields are ordered in ascending order.
   118  		if tagNum < prevTagNum {
   119  			return fmt.Errorf("txRaw must follow ADR-027, got tagNum %d after tagNum %d", tagNum, prevTagNum)
   120  		}
   121  		prevTagNum = tagNum
   122  
   123  		// All 3 fields of TxRaw have wireType == 2, so their next component
   124  		// is a varint, so we can safely call ConsumeVarint here.
   125  		// Byte structure: <varint of bytes length><bytes sequence>
   126  		// Inner  fields are verified in `DefaultTxDecoder`
   127  		lengthPrefix, m := protowire.ConsumeVarint(txBytes[m:])
   128  		if m < 0 {
   129  			return fmt.Errorf("invalid length; %w", protowire.ParseError(m))
   130  		}
   131  		// We make sure that this varint is as short as possible.
   132  		n := varintMinLength(lengthPrefix)
   133  		if n != m {
   134  			return fmt.Errorf("length prefix varint for tagNum %d is not as short as possible, read %d, only need %d", tagNum, m, n)
   135  		}
   136  
   137  		// Skip over the bytes that store fieldNumber and wireType bytes.
   138  		_, _, m = protowire.ConsumeField(txBytes)
   139  		if m < 0 {
   140  			return fmt.Errorf("invalid length; %w", protowire.ParseError(m))
   141  		}
   142  		txBytes = txBytes[m:]
   143  	}
   144  
   145  	return nil
   146  }
   147  
   148  // varintMinLength returns the minimum number of bytes necessary to encode an
   149  // uint using varint encoding.
   150  func varintMinLength(n uint64) int {
   151  	switch {
   152  	// Note: 1<<N == 2**N.
   153  	case n < 1<<(7):
   154  		return 1
   155  	case n < 1<<(7*2):
   156  		return 2
   157  	case n < 1<<(7*3):
   158  		return 3
   159  	case n < 1<<(7*4):
   160  		return 4
   161  	case n < 1<<(7*5):
   162  		return 5
   163  	case n < 1<<(7*6):
   164  		return 6
   165  	case n < 1<<(7*7):
   166  		return 7
   167  	case n < 1<<(7*8):
   168  		return 8
   169  	case n < 1<<(7*9):
   170  		return 9
   171  	default:
   172  		return 10
   173  	}
   174  }