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 }