github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/tx/builder.go (about) 1 package tx 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "github.com/cosmos/gogoproto/proto" 8 protov2 "google.golang.org/protobuf/proto" 9 10 errorsmod "cosmossdk.io/errors" 11 12 "github.com/cosmos/cosmos-sdk/client" 13 "github.com/cosmos/cosmos-sdk/codec" 14 codectypes "github.com/cosmos/cosmos-sdk/codec/types" 15 cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" 16 sdk "github.com/cosmos/cosmos-sdk/types" 17 sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" 18 "github.com/cosmos/cosmos-sdk/types/tx" 19 "github.com/cosmos/cosmos-sdk/types/tx/signing" 20 "github.com/cosmos/cosmos-sdk/x/auth/ante" 21 authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" 22 ) 23 24 // wrapper is a wrapper around the tx.Tx proto.Message which retain the raw 25 // body and auth_info bytes. 26 type wrapper struct { 27 cdc codec.Codec 28 29 tx *tx.Tx 30 31 // bodyBz represents the protobuf encoding of TxBody. This should be encoding 32 // from the client using TxRaw if the tx was decoded from the wire 33 bodyBz []byte 34 35 // authInfoBz represents the protobuf encoding of TxBody. This should be encoding 36 // from the client using TxRaw if the tx was decoded from the wire 37 authInfoBz []byte 38 39 txBodyHasUnknownNonCriticals bool 40 41 signers [][]byte 42 msgsV2 []protov2.Message 43 } 44 45 var ( 46 _ authsigning.Tx = &wrapper{} 47 _ client.TxBuilder = &wrapper{} 48 _ ante.HasExtensionOptionsTx = &wrapper{} 49 _ ExtensionOptionsTxBuilder = &wrapper{} 50 ) 51 52 // ExtensionOptionsTxBuilder defines a TxBuilder that can also set extensions. 53 type ExtensionOptionsTxBuilder interface { 54 client.TxBuilder 55 56 SetExtensionOptions(...*codectypes.Any) 57 SetNonCriticalExtensionOptions(...*codectypes.Any) 58 } 59 60 func newBuilder(cdc codec.Codec) *wrapper { 61 w := &wrapper{ 62 cdc: cdc, 63 tx: &tx.Tx{ 64 Body: &tx.TxBody{}, 65 AuthInfo: &tx.AuthInfo{ 66 Fee: &tx.Fee{}, 67 }, 68 }, 69 } 70 return w 71 } 72 73 func (w *wrapper) GetMsgs() []sdk.Msg { 74 return w.tx.GetMsgs() 75 } 76 77 func (w *wrapper) GetMsgsV2() ([]protov2.Message, error) { 78 if w.msgsV2 == nil { 79 err := w.initSignersAndMsgsV2() 80 if err != nil { 81 return nil, err 82 } 83 } 84 85 return w.msgsV2, nil 86 } 87 88 func (w *wrapper) ValidateBasic() error { 89 if w.tx == nil { 90 return fmt.Errorf("bad Tx") 91 } 92 93 if err := w.tx.ValidateBasic(); err != nil { 94 return err 95 } 96 97 sigs := w.tx.Signatures 98 signers, err := w.GetSigners() 99 if err != nil { 100 return err 101 } 102 103 if len(sigs) != len(signers) { 104 return errorsmod.Wrapf( 105 sdkerrors.ErrUnauthorized, 106 "wrong number of signers; expected %d, got %d", len(signers), len(sigs), 107 ) 108 } 109 110 return nil 111 } 112 113 func (w *wrapper) getBodyBytes() []byte { 114 if len(w.bodyBz) == 0 { 115 // if bodyBz is empty, then marshal the body. bodyBz will generally 116 // be set to nil whenever SetBody is called so the result of calling 117 // this method should always return the correct bytes. Note that after 118 // decoding bodyBz is derived from TxRaw so that it matches what was 119 // transmitted over the wire 120 var err error 121 w.bodyBz, err = proto.Marshal(w.tx.Body) 122 if err != nil { 123 panic(err) 124 } 125 } 126 return w.bodyBz 127 } 128 129 func (w *wrapper) getAuthInfoBytes() []byte { 130 if len(w.authInfoBz) == 0 { 131 // if authInfoBz is empty, then marshal the body. authInfoBz will generally 132 // be set to nil whenever SetAuthInfo is called so the result of calling 133 // this method should always return the correct bytes. Note that after 134 // decoding authInfoBz is derived from TxRaw so that it matches what was 135 // transmitted over the wire 136 var err error 137 w.authInfoBz, err = proto.Marshal(w.tx.AuthInfo) 138 if err != nil { 139 panic(err) 140 } 141 } 142 return w.authInfoBz 143 } 144 145 func (w *wrapper) initSignersAndMsgsV2() error { 146 var err error 147 w.signers, w.msgsV2, err = w.tx.GetSigners(w.cdc) 148 return err 149 } 150 151 func (w *wrapper) GetSigners() ([][]byte, error) { 152 if w.signers == nil { 153 err := w.initSignersAndMsgsV2() 154 if err != nil { 155 return nil, err 156 } 157 } 158 return w.signers, nil 159 } 160 161 func (w *wrapper) GetPubKeys() ([]cryptotypes.PubKey, error) { 162 signerInfos := w.tx.AuthInfo.SignerInfos 163 pks := make([]cryptotypes.PubKey, len(signerInfos)) 164 165 for i, si := range signerInfos { 166 // NOTE: it is okay to leave this nil if there is no PubKey in the SignerInfo. 167 // PubKey's can be left unset in SignerInfo. 168 if si.PublicKey == nil { 169 continue 170 } 171 172 pkAny := si.PublicKey.GetCachedValue() 173 pk, ok := pkAny.(cryptotypes.PubKey) 174 if ok { 175 pks[i] = pk 176 } else { 177 return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "Expecting PubKey, got: %T", pkAny) 178 } 179 } 180 181 return pks, nil 182 } 183 184 func (w *wrapper) GetGas() uint64 { 185 return w.tx.AuthInfo.Fee.GasLimit 186 } 187 188 func (w *wrapper) GetFee() sdk.Coins { 189 return w.tx.AuthInfo.Fee.Amount 190 } 191 192 func (w *wrapper) FeePayer() []byte { 193 feePayer := w.tx.AuthInfo.Fee.Payer 194 if feePayer != "" { 195 feePayerAddr, err := w.cdc.InterfaceRegistry().SigningContext().AddressCodec().StringToBytes(feePayer) 196 if err != nil { 197 panic(err) 198 } 199 return feePayerAddr 200 } 201 202 // use first signer as default if no payer specified 203 signers, err := w.GetSigners() 204 if err != nil { 205 return nil 206 } 207 208 return signers[0] 209 } 210 211 func (w *wrapper) FeeGranter() []byte { 212 return w.tx.FeeGranter(w.cdc) 213 } 214 215 func (w *wrapper) GetMemo() string { 216 return w.tx.Body.Memo 217 } 218 219 // GetTimeoutHeight returns the transaction's timeout height (if set). 220 func (w *wrapper) GetTimeoutHeight() uint64 { 221 return w.tx.Body.TimeoutHeight 222 } 223 224 func (w *wrapper) GetSignaturesV2() ([]signing.SignatureV2, error) { 225 signerInfos := w.tx.AuthInfo.SignerInfos 226 sigs := w.tx.Signatures 227 pubKeys, err := w.GetPubKeys() 228 if err != nil { 229 return nil, err 230 } 231 n := len(signerInfos) 232 res := make([]signing.SignatureV2, n) 233 234 for i, si := range signerInfos { 235 // handle nil signatures (in case of simulation) 236 if si.ModeInfo == nil { 237 res[i] = signing.SignatureV2{ 238 PubKey: pubKeys[i], 239 } 240 } else { 241 var err error 242 sigData, err := ModeInfoAndSigToSignatureData(si.ModeInfo, sigs[i]) 243 if err != nil { 244 return nil, err 245 } 246 // sequence number is functionally a transaction nonce and referred to as such in the SDK 247 nonce := si.GetSequence() 248 res[i] = signing.SignatureV2{ 249 PubKey: pubKeys[i], 250 Data: sigData, 251 Sequence: nonce, 252 } 253 254 } 255 } 256 257 return res, nil 258 } 259 260 func (w *wrapper) SetMsgs(msgs ...sdk.Msg) error { 261 anys, err := tx.SetMsgs(msgs) 262 if err != nil { 263 return err 264 } 265 266 w.tx.Body.Messages = anys 267 268 // set bodyBz to nil because the cached bodyBz no longer matches tx.Body 269 w.bodyBz = nil 270 271 // reset signers and msgsV2 272 w.signers = nil 273 w.msgsV2 = nil 274 275 return nil 276 } 277 278 // SetTimeoutHeight sets the transaction's height timeout. 279 func (w *wrapper) SetTimeoutHeight(height uint64) { 280 w.tx.Body.TimeoutHeight = height 281 282 // set bodyBz to nil because the cached bodyBz no longer matches tx.Body 283 w.bodyBz = nil 284 } 285 286 func (w *wrapper) SetMemo(memo string) { 287 w.tx.Body.Memo = memo 288 289 // set bodyBz to nil because the cached bodyBz no longer matches tx.Body 290 w.bodyBz = nil 291 } 292 293 func (w *wrapper) SetGasLimit(limit uint64) { 294 if w.tx.AuthInfo.Fee == nil { 295 w.tx.AuthInfo.Fee = &tx.Fee{} 296 } 297 298 w.tx.AuthInfo.Fee.GasLimit = limit 299 300 // set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo 301 w.authInfoBz = nil 302 } 303 304 func (w *wrapper) SetFeeAmount(coins sdk.Coins) { 305 if w.tx.AuthInfo.Fee == nil { 306 w.tx.AuthInfo.Fee = &tx.Fee{} 307 } 308 309 w.tx.AuthInfo.Fee.Amount = coins 310 311 // set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo 312 w.authInfoBz = nil 313 } 314 315 func (w *wrapper) SetFeePayer(feePayer sdk.AccAddress) { 316 if w.tx.AuthInfo.Fee == nil { 317 w.tx.AuthInfo.Fee = &tx.Fee{} 318 } 319 320 w.tx.AuthInfo.Fee.Payer = feePayer.String() 321 322 // set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo 323 w.authInfoBz = nil 324 } 325 326 func (w *wrapper) SetFeeGranter(feeGranter sdk.AccAddress) { 327 if w.tx.AuthInfo.Fee == nil { 328 w.tx.AuthInfo.Fee = &tx.Fee{} 329 } 330 331 w.tx.AuthInfo.Fee.Granter = feeGranter.String() 332 333 // set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo 334 w.authInfoBz = nil 335 } 336 337 func (w *wrapper) SetSignatures(signatures ...signing.SignatureV2) error { 338 n := len(signatures) 339 signerInfos := make([]*tx.SignerInfo, n) 340 rawSigs := make([][]byte, n) 341 342 for i, sig := range signatures { 343 var ( 344 modeInfo *tx.ModeInfo 345 pubKey *codectypes.Any 346 err error 347 ) 348 modeInfo, rawSigs[i] = SignatureDataToModeInfoAndSig(sig.Data) 349 if sig.PubKey != nil { 350 pubKey, err = codectypes.NewAnyWithValue(sig.PubKey) 351 if err != nil { 352 return err 353 } 354 } 355 signerInfos[i] = &tx.SignerInfo{ 356 PublicKey: pubKey, 357 ModeInfo: modeInfo, 358 Sequence: sig.Sequence, 359 } 360 } 361 362 w.setSignerInfos(signerInfos) 363 w.setSignatures(rawSigs) 364 365 return nil 366 } 367 368 func (w *wrapper) setSignerInfos(infos []*tx.SignerInfo) { 369 w.tx.AuthInfo.SignerInfos = infos 370 // set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo 371 w.authInfoBz = nil 372 } 373 374 func (w *wrapper) setSignerInfoAtIndex(index int, info *tx.SignerInfo) { 375 signers, err := w.GetSigners() 376 if err != nil { 377 panic(err) 378 } 379 380 if w.tx.AuthInfo.SignerInfos == nil { 381 w.tx.AuthInfo.SignerInfos = make([]*tx.SignerInfo, len(signers)) 382 } 383 384 w.tx.AuthInfo.SignerInfos[index] = info 385 // set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo 386 w.authInfoBz = nil 387 } 388 389 func (w *wrapper) setSignatures(sigs [][]byte) { 390 w.tx.Signatures = sigs 391 } 392 393 func (w *wrapper) setSignatureAtIndex(index int, sig []byte) { 394 signers, err := w.GetSigners() 395 if err != nil { 396 panic(err) 397 } 398 399 if w.tx.Signatures == nil { 400 w.tx.Signatures = make([][]byte, len(signers)) 401 } 402 403 w.tx.Signatures[index] = sig 404 } 405 406 func (w *wrapper) GetTx() authsigning.Tx { 407 return w 408 } 409 410 func (w *wrapper) GetProtoTx() *tx.Tx { 411 return w.tx 412 } 413 414 // Deprecated: AsAny extracts proto Tx and wraps it into Any. 415 // NOTE: You should probably use `GetProtoTx` if you want to serialize the transaction. 416 func (w *wrapper) AsAny() *codectypes.Any { 417 return codectypes.UnsafePackAny(w.tx) 418 } 419 420 // WrapTx creates a TxBuilder wrapper around a tx.Tx proto message. 421 func WrapTx(protoTx *tx.Tx) client.TxBuilder { 422 return &wrapper{ 423 tx: protoTx, 424 } 425 } 426 427 func (w *wrapper) GetExtensionOptions() []*codectypes.Any { 428 return w.tx.Body.ExtensionOptions 429 } 430 431 func (w *wrapper) GetNonCriticalExtensionOptions() []*codectypes.Any { 432 return w.tx.Body.NonCriticalExtensionOptions 433 } 434 435 func (w *wrapper) SetExtensionOptions(extOpts ...*codectypes.Any) { 436 w.tx.Body.ExtensionOptions = extOpts 437 w.bodyBz = nil 438 } 439 440 func (w *wrapper) SetNonCriticalExtensionOptions(extOpts ...*codectypes.Any) { 441 w.tx.Body.NonCriticalExtensionOptions = extOpts 442 w.bodyBz = nil 443 } 444 445 func (w *wrapper) AddAuxSignerData(data tx.AuxSignerData) error { 446 err := data.ValidateBasic() 447 if err != nil { 448 return err 449 } 450 451 w.bodyBz = data.SignDoc.BodyBytes 452 453 var body tx.TxBody 454 err = w.cdc.Unmarshal(w.bodyBz, &body) 455 if err != nil { 456 return err 457 } 458 459 if w.tx.Body.Memo != "" && w.tx.Body.Memo != body.Memo { 460 return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has memo %s, got %s in AuxSignerData", w.tx.Body.Memo, body.Memo) 461 } 462 if w.tx.Body.TimeoutHeight != 0 && w.tx.Body.TimeoutHeight != body.TimeoutHeight { 463 return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has timeout height %d, got %d in AuxSignerData", w.tx.Body.TimeoutHeight, body.TimeoutHeight) 464 } 465 if len(w.tx.Body.ExtensionOptions) != 0 { 466 if len(w.tx.Body.ExtensionOptions) != len(body.ExtensionOptions) { 467 return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has %d extension options, got %d in AuxSignerData", len(w.tx.Body.ExtensionOptions), len(body.ExtensionOptions)) 468 } 469 for i, o := range w.tx.Body.ExtensionOptions { 470 if !o.Equal(body.ExtensionOptions[i]) { 471 return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has extension option %+v at index %d, got %+v in AuxSignerData", o, i, body.ExtensionOptions[i]) 472 } 473 } 474 } 475 if len(w.tx.Body.NonCriticalExtensionOptions) != 0 { 476 if len(w.tx.Body.NonCriticalExtensionOptions) != len(body.NonCriticalExtensionOptions) { 477 return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has %d non-critical extension options, got %d in AuxSignerData", len(w.tx.Body.NonCriticalExtensionOptions), len(body.NonCriticalExtensionOptions)) 478 } 479 for i, o := range w.tx.Body.NonCriticalExtensionOptions { 480 if !o.Equal(body.NonCriticalExtensionOptions[i]) { 481 return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has non-critical extension option %+v at index %d, got %+v in AuxSignerData", o, i, body.NonCriticalExtensionOptions[i]) 482 } 483 } 484 } 485 if len(w.tx.Body.Messages) != 0 { 486 if len(w.tx.Body.Messages) != len(body.Messages) { 487 return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has %d Msgs, got %d in AuxSignerData", len(w.tx.Body.Messages), len(body.Messages)) 488 } 489 for i, o := range w.tx.Body.Messages { 490 if !o.Equal(body.Messages[i]) { 491 return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has Msg %+v at index %d, got %+v in AuxSignerData", o, i, body.Messages[i]) 492 } 493 } 494 } 495 496 w.SetMemo(body.Memo) 497 w.SetTimeoutHeight(body.TimeoutHeight) 498 w.SetExtensionOptions(body.ExtensionOptions...) 499 w.SetNonCriticalExtensionOptions(body.NonCriticalExtensionOptions...) 500 msgs := make([]sdk.Msg, len(body.Messages)) 501 for i, msgAny := range body.Messages { 502 msgs[i] = msgAny.GetCachedValue().(sdk.Msg) 503 } 504 err = w.SetMsgs(msgs...) 505 if err != nil { 506 return err 507 } 508 509 // Get the aux signer's index in GetSigners. 510 signerIndex := -1 511 signers, err := w.GetSigners() 512 if err != nil { 513 return err 514 } 515 516 for i, signer := range signers { 517 addrBz, err := w.cdc.InterfaceRegistry().SigningContext().AddressCodec().StringToBytes(data.Address) 518 if err != nil { 519 return err 520 } 521 if bytes.Equal(signer, addrBz) { 522 signerIndex = i 523 } 524 } 525 if signerIndex < 0 { 526 return sdkerrors.ErrLogic.Wrapf("address %s is not a signer", data.Address) 527 } 528 529 w.setSignerInfoAtIndex(signerIndex, &tx.SignerInfo{ 530 PublicKey: data.SignDoc.PublicKey, 531 ModeInfo: &tx.ModeInfo{Sum: &tx.ModeInfo_Single_{Single: &tx.ModeInfo_Single{Mode: data.Mode}}}, 532 Sequence: data.SignDoc.Sequence, 533 }) 534 w.setSignatureAtIndex(signerIndex, data.Sig) 535 536 return nil 537 }