github.com/Finschia/finschia-sdk@v0.49.1/x/auth/tx/builder.go (about) 1 package tx 2 3 import ( 4 "github.com/gogo/protobuf/proto" 5 6 "github.com/Finschia/finschia-sdk/client" 7 codectypes "github.com/Finschia/finschia-sdk/codec/types" 8 cryptotypes "github.com/Finschia/finschia-sdk/crypto/types" 9 sdk "github.com/Finschia/finschia-sdk/types" 10 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 11 "github.com/Finschia/finschia-sdk/types/tx" 12 "github.com/Finschia/finschia-sdk/types/tx/signing" 13 "github.com/Finschia/finschia-sdk/x/auth/ante" 14 authsigning "github.com/Finschia/finschia-sdk/x/auth/signing" 15 ) 16 17 // wrapper is a wrapper around the tx.Tx proto.Message which retain the raw 18 // body and auth_info bytes. 19 type wrapper struct { 20 tx *tx.Tx 21 22 // bodyBz represents the protobuf encoding of TxBody. This should be encoding 23 // from the client using TxRaw if the tx was decoded from the wire 24 bodyBz []byte 25 26 // authInfoBz represents the protobuf encoding of TxBody. This should be encoding 27 // from the client using TxRaw if the tx was decoded from the wire 28 authInfoBz []byte 29 30 txBodyHasUnknownNonCriticals bool 31 } 32 33 var ( 34 _ authsigning.Tx = &wrapper{} 35 _ client.TxBuilder = &wrapper{} 36 _ ante.HasExtensionOptionsTx = &wrapper{} 37 _ ExtensionOptionsTxBuilder = &wrapper{} 38 ) 39 40 // ExtensionOptionsTxBuilder defines a TxBuilder that can also set extensions. 41 type ExtensionOptionsTxBuilder interface { 42 client.TxBuilder 43 44 SetExtensionOptions(...*codectypes.Any) 45 SetNonCriticalExtensionOptions(...*codectypes.Any) 46 } 47 48 func newBuilder() *wrapper { 49 return &wrapper{ 50 tx: &tx.Tx{ 51 Body: &tx.TxBody{}, 52 AuthInfo: &tx.AuthInfo{ 53 Fee: &tx.Fee{}, 54 }, 55 }, 56 } 57 } 58 59 func (w *wrapper) GetMsgs() []sdk.Msg { 60 return w.tx.GetMsgs() 61 } 62 63 func (w *wrapper) ValidateBasic() error { 64 return w.tx.ValidateBasic() 65 } 66 67 func (w *wrapper) getBodyBytes() []byte { 68 if len(w.bodyBz) == 0 { 69 // if bodyBz is empty, then marshal the body. bodyBz will generally 70 // be set to nil whenever SetBody is called so the result of calling 71 // this method should always return the correct bytes. Note that after 72 // decoding bodyBz is derived from TxRaw so that it matches what was 73 // transmitted over the wire 74 var err error 75 w.bodyBz, err = proto.Marshal(w.tx.Body) 76 if err != nil { 77 panic(err) 78 } 79 } 80 return w.bodyBz 81 } 82 83 func (w *wrapper) getAuthInfoBytes() []byte { 84 if len(w.authInfoBz) == 0 { 85 // if authInfoBz is empty, then marshal the body. authInfoBz will generally 86 // be set to nil whenever SetAuthInfo is called so the result of calling 87 // this method should always return the correct bytes. Note that after 88 // decoding authInfoBz is derived from TxRaw so that it matches what was 89 // transmitted over the wire 90 var err error 91 w.authInfoBz, err = proto.Marshal(w.tx.AuthInfo) 92 if err != nil { 93 panic(err) 94 } 95 } 96 return w.authInfoBz 97 } 98 99 func (w *wrapper) GetSigners() []sdk.AccAddress { 100 return w.tx.GetSigners() 101 } 102 103 func (w *wrapper) GetPubKeys() ([]cryptotypes.PubKey, error) { 104 signerInfos := w.tx.AuthInfo.SignerInfos 105 pks := make([]cryptotypes.PubKey, len(signerInfos)) 106 107 for i, si := range signerInfos { 108 // NOTE: it is okay to leave this nil if there is no PubKey in the SignerInfo. 109 // PubKey's can be left unset in SignerInfo. 110 if si.PublicKey == nil { 111 continue 112 } 113 114 pkAny := si.PublicKey.GetCachedValue() 115 pk, ok := pkAny.(cryptotypes.PubKey) 116 if ok { 117 pks[i] = pk 118 } else { 119 return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic, "Expecting PubKey, got: %T", pkAny) 120 } 121 } 122 123 return pks, nil 124 } 125 126 func (w *wrapper) GetGas() uint64 { 127 return w.tx.AuthInfo.Fee.GasLimit 128 } 129 130 func (w *wrapper) GetFee() sdk.Coins { 131 return w.tx.AuthInfo.Fee.Amount 132 } 133 134 func (w *wrapper) FeePayer() sdk.AccAddress { 135 feePayer := w.tx.AuthInfo.Fee.Payer 136 if feePayer != "" { 137 return sdk.MustAccAddressFromBech32(feePayer) 138 } 139 // use first signer as default if no payer specified 140 return w.GetSigners()[0] 141 } 142 143 func (w *wrapper) FeeGranter() sdk.AccAddress { 144 feePayer := w.tx.AuthInfo.Fee.Granter 145 if feePayer != "" { 146 return sdk.MustAccAddressFromBech32(feePayer) 147 } 148 return nil 149 } 150 151 func (w *wrapper) GetMemo() string { 152 return w.tx.Body.Memo 153 } 154 155 // GetTimeoutHeight returns the transaction's timeout height (if set). 156 func (w *wrapper) GetTimeoutHeight() uint64 { 157 return w.tx.Body.TimeoutHeight 158 } 159 160 func (w *wrapper) GetSignaturesV2() ([]signing.SignatureV2, error) { 161 signerInfos := w.tx.AuthInfo.SignerInfos 162 sigs := w.tx.Signatures 163 pubKeys, err := w.GetPubKeys() 164 if err != nil { 165 return nil, err 166 } 167 n := len(signerInfos) 168 res := make([]signing.SignatureV2, n) 169 170 for i, si := range signerInfos { 171 // handle nil signatures (in case of simulation) 172 if si.ModeInfo == nil { 173 res[i] = signing.SignatureV2{ 174 PubKey: pubKeys[i], 175 } 176 } else { 177 var err error 178 sigData, err := ModeInfoAndSigToSignatureData(si.ModeInfo, sigs[i]) 179 if err != nil { 180 return nil, err 181 } 182 res[i] = signing.SignatureV2{ 183 PubKey: pubKeys[i], 184 Data: sigData, 185 Sequence: si.GetSequence(), 186 } 187 188 } 189 } 190 191 return res, nil 192 } 193 194 func (w *wrapper) SetMsgs(msgs ...sdk.Msg) error { 195 anys := make([]*codectypes.Any, len(msgs)) 196 197 for i, msg := range msgs { 198 var err error 199 anys[i], err = codectypes.NewAnyWithValue(msg) 200 if err != nil { 201 return err 202 } 203 } 204 205 w.tx.Body.Messages = anys 206 207 // set bodyBz to nil because the cached bodyBz no longer matches tx.Body 208 w.bodyBz = nil 209 210 return nil 211 } 212 213 // SetTimeoutHeight sets the transaction's height timeout. 214 func (w *wrapper) SetTimeoutHeight(height uint64) { 215 w.tx.Body.TimeoutHeight = height 216 217 // set bodyBz to nil because the cached bodyBz no longer matches tx.Body 218 w.bodyBz = nil 219 } 220 221 func (w *wrapper) SetMemo(memo string) { 222 w.tx.Body.Memo = memo 223 224 // set bodyBz to nil because the cached bodyBz no longer matches tx.Body 225 w.bodyBz = nil 226 } 227 228 func (w *wrapper) SetGasLimit(limit uint64) { 229 if w.tx.AuthInfo.Fee == nil { 230 w.tx.AuthInfo.Fee = &tx.Fee{} 231 } 232 233 w.tx.AuthInfo.Fee.GasLimit = limit 234 235 // set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo 236 w.authInfoBz = nil 237 } 238 239 func (w *wrapper) SetFeeAmount(coins sdk.Coins) { 240 if w.tx.AuthInfo.Fee == nil { 241 w.tx.AuthInfo.Fee = &tx.Fee{} 242 } 243 244 w.tx.AuthInfo.Fee.Amount = coins 245 246 // set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo 247 w.authInfoBz = nil 248 } 249 250 func (w *wrapper) SetFeePayer(feePayer sdk.AccAddress) { 251 if w.tx.AuthInfo.Fee == nil { 252 w.tx.AuthInfo.Fee = &tx.Fee{} 253 } 254 255 w.tx.AuthInfo.Fee.Payer = feePayer.String() 256 257 // set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo 258 w.authInfoBz = nil 259 } 260 261 func (w *wrapper) SetFeeGranter(feeGranter sdk.AccAddress) { 262 if w.tx.AuthInfo.Fee == nil { 263 w.tx.AuthInfo.Fee = &tx.Fee{} 264 } 265 266 w.tx.AuthInfo.Fee.Granter = feeGranter.String() 267 268 // set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo 269 w.authInfoBz = nil 270 } 271 272 func (w *wrapper) SetSignatures(signatures ...signing.SignatureV2) error { 273 n := len(signatures) 274 signerInfos := make([]*tx.SignerInfo, n) 275 rawSigs := make([][]byte, n) 276 277 for i, sig := range signatures { 278 var modeInfo *tx.ModeInfo 279 modeInfo, rawSigs[i] = SignatureDataToModeInfoAndSig(sig.Data) 280 any, err := codectypes.NewAnyWithValue(sig.PubKey) 281 if err != nil { 282 return err 283 } 284 signerInfos[i] = &tx.SignerInfo{ 285 PublicKey: any, 286 ModeInfo: modeInfo, 287 Sequence: sig.Sequence, 288 } 289 } 290 291 w.setSignerInfos(signerInfos) 292 w.setSignatures(rawSigs) 293 294 return nil 295 } 296 297 func (w *wrapper) setSignerInfos(infos []*tx.SignerInfo) { 298 w.tx.AuthInfo.SignerInfos = infos 299 // set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo 300 w.authInfoBz = nil 301 } 302 303 func (w *wrapper) setSignatures(sigs [][]byte) { 304 w.tx.Signatures = sigs 305 } 306 307 func (w *wrapper) GetTx() authsigning.Tx { 308 return w 309 } 310 311 func (w *wrapper) GetProtoTx() *tx.Tx { 312 return w.tx 313 } 314 315 // Deprecated: AsAny extracts proto Tx and wraps it into Any. 316 // NOTE: You should probably use `GetProtoTx` if you want to serialize the transaction. 317 func (w *wrapper) AsAny() *codectypes.Any { 318 return codectypes.UnsafePackAny(w.tx) 319 } 320 321 // WrapTx creates a TxBuilder wrapper around a tx.Tx proto message. 322 func WrapTx(protoTx *tx.Tx) client.TxBuilder { 323 return &wrapper{ 324 tx: protoTx, 325 } 326 } 327 328 func (w *wrapper) GetExtensionOptions() []*codectypes.Any { 329 return w.tx.Body.ExtensionOptions 330 } 331 332 func (w *wrapper) GetNonCriticalExtensionOptions() []*codectypes.Any { 333 return w.tx.Body.NonCriticalExtensionOptions 334 } 335 336 func (w *wrapper) SetExtensionOptions(extOpts ...*codectypes.Any) { 337 w.tx.Body.ExtensionOptions = extOpts 338 w.bodyBz = nil 339 } 340 341 func (w *wrapper) SetNonCriticalExtensionOptions(extOpts ...*codectypes.Any) { 342 w.tx.Body.NonCriticalExtensionOptions = extOpts 343 w.bodyBz = nil 344 }