github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/auth/ibc-tx/decoder.go (about) 1 package ibc_tx 2 3 import ( 4 "fmt" 5 6 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 7 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec/unknownproto" 8 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/types" 9 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 10 ibctx "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/ibc-adapter" 11 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/tx/signing" 12 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/ibc-tx/internal/adapter" 13 "google.golang.org/protobuf/encoding/protowire" 14 15 //"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec/unknownproto" 16 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 17 18 tx "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/tx" 19 authtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types" 20 ) 21 22 func CM40TxDecoder(cdc codec.ProtoCodecMarshaler) func(txBytes []byte) (ibctx.Tx, error) { 23 return func(txBytes []byte) (ibctx.Tx, error) { 24 // Make sure txBytes follow ADR-027. 25 err := rejectNonADR027TxRaw(txBytes) 26 if err != nil { 27 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 28 } 29 30 var raw tx.TxRaw 31 32 // reject all unknown proto fields in the root TxRaw 33 err = unknownproto.RejectUnknownFieldsStrict(txBytes, &raw, cdc.InterfaceRegistry()) 34 if err != nil { 35 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 36 } 37 38 err = cdc.UnmarshalBinaryBare(txBytes, &raw) 39 if err != nil { 40 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 41 } 42 43 var body tx.TxBody 44 // allow non-critical unknown fields in TxBody 45 txBodyHasUnknownNonCriticals, err := unknownproto.RejectUnknownFields(raw.BodyBytes, &body, true, cdc.InterfaceRegistry()) 46 if err != nil { 47 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 48 } 49 50 err = cdc.UnmarshalBinaryBare(raw.BodyBytes, &body) 51 if err != nil { 52 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 53 } 54 55 var authInfo tx.AuthInfo 56 57 // reject all unknown proto fields in AuthInfo 58 err = unknownproto.RejectUnknownFieldsStrict(raw.AuthInfoBytes, &authInfo, cdc.InterfaceRegistry()) 59 if err != nil { 60 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 61 } 62 63 err = cdc.UnmarshalBinaryBare(raw.AuthInfoBytes, &authInfo) 64 if err != nil { 65 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 66 } 67 68 ibcTx := &tx.Tx{ 69 Body: &body, 70 AuthInfo: &authInfo, 71 Signatures: raw.Signatures, 72 } 73 return &wrapper{ 74 tx: ibcTx, 75 bodyBz: raw.BodyBytes, 76 authInfoBz: raw.AuthInfoBytes, 77 txBodyHasUnknownNonCriticals: txBodyHasUnknownNonCriticals, 78 }, nil 79 } 80 } 81 82 // DefaultTxDecoder returns a default protobuf TxDecoder using the provided Marshaler. 83 // func IbcTxDecoder(cdc codec.ProtoCodecMarshaler) ibcadapter.TxDecoder { 84 func IbcTxDecoder(cdc codec.ProtoCodecMarshaler) ibctx.IbcTxDecoder { 85 return func(txBytes []byte) (*authtypes.IbcTx, error) { 86 // Make sure txBytes follow ADR-027. 87 err := rejectNonADR027TxRaw(txBytes) 88 if err != nil { 89 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 90 } 91 92 var raw tx.TxRaw 93 94 // reject all unknown proto fields in the root TxRaw 95 err = unknownproto.RejectUnknownFieldsStrict(txBytes, &raw, cdc.InterfaceRegistry()) 96 if err != nil { 97 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 98 } 99 100 err = cdc.UnmarshalBinaryBare(txBytes, &raw) 101 if err != nil { 102 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 103 } 104 105 var body tx.TxBody 106 // allow non-critical unknown fields in TxBody 107 txBodyHasUnknownNonCriticals, err := unknownproto.RejectUnknownFields(raw.BodyBytes, &body, true, cdc.InterfaceRegistry()) 108 if err != nil { 109 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 110 } 111 112 err = cdc.UnmarshalBinaryBare(raw.BodyBytes, &body) 113 if err != nil { 114 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 115 } 116 117 var authInfo tx.AuthInfo 118 119 // reject all unknown proto fields in AuthInfo 120 err = unknownproto.RejectUnknownFieldsStrict(raw.AuthInfoBytes, &authInfo, cdc.InterfaceRegistry()) 121 if err != nil { 122 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 123 } 124 125 err = cdc.UnmarshalBinaryBare(raw.AuthInfoBytes, &authInfo) 126 if err != nil { 127 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 128 } 129 130 ibcTx := &tx.Tx{ 131 Body: &body, 132 AuthInfo: &authInfo, 133 Signatures: raw.Signatures, 134 } 135 fee, signFee, payer, err := convertFee(authInfo) 136 if err != nil { 137 return nil, err 138 } 139 140 signatures := convertSignature(ibcTx) 141 142 // construct Msg 143 stdMsgs, signMsgs, err := constructMsgs(ibcTx) 144 if err != nil { 145 return nil, err 146 } 147 148 var signMode []signing.SignMode 149 if authInfo.SignerInfos != nil { 150 for _, signInfo := range authInfo.SignerInfos { 151 modeInfo, ok := signInfo.ModeInfo.Sum.(*tx.ModeInfo_Single_) 152 if !ok { 153 return nil, sdkerrors.Wrap(sdkerrors.ErrInternal, "only support ModeInfo_Single") 154 } 155 signMode = append(signMode, modeInfo.Single.Mode) 156 } 157 } 158 159 sequences := []uint64{} 160 for _, seq := range authInfo.SignerInfos { 161 sequences = append(sequences, seq.Sequence) 162 } 163 hasExtensionOpt := false 164 if len(body.ExtensionOptions) != 0 || len(body.NonCriticalExtensionOptions) != 0 { 165 hasExtensionOpt = true 166 } 167 168 stx := authtypes.IbcTx{ 169 &authtypes.StdTx{ 170 Msgs: stdMsgs, 171 Fee: fee, 172 Signatures: signatures, 173 Memo: ibcTx.Body.Memo, 174 }, 175 raw.AuthInfoBytes, 176 raw.BodyBytes, 177 signMode, 178 signFee, 179 signMsgs, 180 sequences, 181 txBodyHasUnknownNonCriticals, 182 hasExtensionOpt, 183 payer, 184 ValidateParams(ibcTx), 185 } 186 187 return &stx, nil 188 } 189 } 190 191 func ValidateParams(ibcTx *tx.Tx) func() error { 192 return func() error { 193 if ibcTx.AuthInfo == nil { 194 return sdkerrors.Wrap(sdkerrors.ErrTxDecode, "missing AuthInfo") 195 } 196 if ibcTx.AuthInfo.Fee == nil { 197 return sdkerrors.Wrap(sdkerrors.ErrTxDecode, "missing AuthInfo Fee") 198 } 199 return nil 200 } 201 } 202 203 func constructMsgs(ibcTx *tx.Tx) ([]sdk.Msg, []sdk.Msg, error) { 204 var err error 205 stdMsgs, signMsgs := []sdk.Msg{}, []sdk.Msg{} 206 for _, ibcMsg := range ibcTx.Body.Messages { 207 m, ok := ibcMsg.GetCachedValue().(sdk.Msg) 208 if !ok { 209 return nil, nil, sdkerrors.Wrap( 210 sdkerrors.ErrInternal, "messages in ibcTx.Body not implement sdk.Msg", 211 ) 212 } 213 var newMsg sdk.Msg 214 switch msg := m.(type) { 215 case DenomAdapterMsg: 216 // ibc transfer fibo is not allowed,should do filter 217 newMsg, err = msg.RulesFilter() 218 if err != nil { 219 return nil, nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "ibc tx decoder not support fibo amount") 220 } 221 default: 222 newMsg = m 223 } 224 stdMsgs = append(stdMsgs, newMsg) 225 signMsgs = append(signMsgs, m) 226 } 227 return stdMsgs, signMsgs, nil 228 } 229 230 func convertSignature(ibcTx *tx.Tx) []authtypes.StdSignature { 231 ret := make([]authtypes.StdSignature, len(ibcTx.Signatures)) 232 233 for i, s := range ibcTx.Signatures { 234 var pkData types.PubKey 235 if ibcTx.AuthInfo.SignerInfos != nil { 236 var ok bool 237 if ibcTx.AuthInfo.SignerInfos[i].PublicKey == nil { 238 // maybe it is a simulate request 239 ret[i] = authtypes.StdSignature{ 240 Signature: s, 241 PubKey: nil, 242 } 243 continue 244 } 245 pkData, ok = ibcTx.AuthInfo.SignerInfos[i].PublicKey.GetCachedValue().(types.PubKey) 246 if !ok { 247 return []authtypes.StdSignature{} 248 } 249 } 250 pubKey, err := adapter.ProtoBufPubkey2LagacyPubkey(pkData) 251 if err != nil { 252 return []authtypes.StdSignature{} 253 } 254 255 ret[i] = authtypes.StdSignature{ 256 Signature: s, 257 PubKey: pubKey, 258 } 259 } 260 261 return ret 262 } 263 264 func convertFee(authInfo tx.AuthInfo) (authtypes.StdFee, authtypes.IbcFee, string, error) { 265 266 gaslimit := uint64(0) 267 var decCoins sdk.DecCoins 268 var err error 269 payer := "" 270 // for verify signature 271 var signFee authtypes.IbcFee 272 if authInfo.Fee != nil { 273 decCoins, err = feeDenomFilter(authInfo.Fee.Amount) 274 if err != nil { 275 return authtypes.StdFee{}, authtypes.IbcFee{}, payer, err 276 } 277 gaslimit = authInfo.Fee.GasLimit 278 signFee = authtypes.IbcFee{ 279 authInfo.Fee.Amount, 280 authInfo.Fee.GasLimit, 281 } 282 payer = authInfo.Fee.Payer 283 } 284 285 return authtypes.StdFee{ 286 Amount: decCoins, 287 Gas: gaslimit, 288 }, signFee, payer, nil 289 } 290 291 func feeDenomFilter(coins sdk.CoinAdapters) (sdk.DecCoins, error) { 292 decCoins := sdk.DecCoins{} 293 294 if coins != nil { 295 for _, fee := range coins { 296 amount := fee.Amount.BigInt() 297 denom := fee.Denom 298 // convert ibc denom to DefaultBondDenom 299 if denom == sdk.DefaultIbcWei { 300 decCoins = append(decCoins, sdk.DecCoin{ 301 Denom: sdk.DefaultBondDenom, 302 Amount: sdk.NewDecFromIntWithPrec(sdk.NewIntFromBigInt(amount), sdk.Precision), 303 }) 304 } else { 305 // not suport other denom fee 306 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "ibc tx decoder only support wei fee") 307 } 308 } 309 } 310 return decCoins, nil 311 } 312 313 // DefaultJSONTxDecoder returns a default protobuf JSON TxDecoder using the provided Marshaler. 314 //func DefaultJSONTxDecoder(cdc codec.ProtoCodecMarshaler) sdk.TxDecoder { 315 // return func(txBytes []byte) (sdk.Tx, error) { 316 // var theTx tx.Tx 317 // err := cdc.UnmarshalJSON(txBytes, &theTx) 318 // if err != nil { 319 // return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) 320 // } 321 // 322 // return &wrapper{ 323 // tx: &theTx, 324 // }, nil 325 // } 326 //} 327 328 // rejectNonADR027TxRaw rejects txBytes that do not follow ADR-027. This is NOT 329 // a generic ADR-027 checker, it only applies decoding TxRaw. Specifically, it 330 // only checks that: 331 // - field numbers are in ascending order (1, 2, and potentially multiple 3s), 332 // - and varints are as short as possible. 333 // All other ADR-027 edge cases (e.g. default values) are not applicable with 334 // TxRaw. 335 func rejectNonADR027TxRaw(txBytes []byte) error { 336 // Make sure all fields are ordered in ascending order with this variable. 337 prevTagNum := protowire.Number(0) 338 339 for len(txBytes) > 0 { 340 tagNum, wireType, m := protowire.ConsumeTag(txBytes) 341 if m < 0 { 342 return fmt.Errorf("invalid length; %w", protowire.ParseError(m)) 343 } 344 // TxRaw only has bytes fields. 345 if wireType != protowire.BytesType { 346 return fmt.Errorf("expected %d wire type, got %d", protowire.BytesType, wireType) 347 } 348 // Make sure fields are ordered in ascending order. 349 if tagNum < prevTagNum { 350 return fmt.Errorf("txRaw must follow ADR-027, got tagNum %d after tagNum %d", tagNum, prevTagNum) 351 } 352 prevTagNum = tagNum 353 354 // All 3 fields of TxRaw have wireType == 2, so their next component 355 // is a varint, so we can safely call ConsumeVarint here. 356 // Byte structure: <varint of bytes length><bytes sequence> 357 // Inner fields are verified in `DefaultTxDecoder` 358 lengthPrefix, m := protowire.ConsumeVarint(txBytes[m:]) 359 if m < 0 { 360 return fmt.Errorf("invalid length; %w", protowire.ParseError(m)) 361 } 362 // We make sure that this varint is as short as possible. 363 n := varintMinLength(lengthPrefix) 364 if n != m { 365 return fmt.Errorf("length prefix varint for tagNum %d is not as short as possible, read %d, only need %d", tagNum, m, n) 366 } 367 368 // Skip over the bytes that store fieldNumber and wireType bytes. 369 _, _, m = protowire.ConsumeField(txBytes) 370 if m < 0 { 371 return fmt.Errorf("invalid length; %w", protowire.ParseError(m)) 372 } 373 txBytes = txBytes[m:] 374 } 375 376 return nil 377 } 378 379 // varintMinLength returns the minimum number of bytes necessary to encode an 380 // uint using varint encoding. 381 func varintMinLength(n uint64) int { 382 switch { 383 // Note: 1<<N == 2**N. 384 case n < 1<<(7): 385 return 1 386 case n < 1<<(7*2): 387 return 2 388 case n < 1<<(7*3): 389 return 3 390 case n < 1<<(7*4): 391 return 4 392 case n < 1<<(7*5): 393 return 5 394 case n < 1<<(7*6): 395 return 6 396 case n < 1<<(7*7): 397 return 7 398 case n < 1<<(7*8): 399 return 8 400 case n < 1<<(7*9): 401 return 9 402 default: 403 return 10 404 } 405 }