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 }