github.com/Finschia/finschia-sdk@v0.49.1/x/auth/tx/decoder.go (about)

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