-
Notifications
You must be signed in to change notification settings - Fork 3.7k
/
sigverify.go
706 lines (604 loc) · 23.2 KB
/
sigverify.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
package ante
import (
"context"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
secp256k1dcrd "github.com/decred/dcrd/dcrec/secp256k1/v4"
"google.golang.org/protobuf/types/known/anypb"
"cosmossdk.io/core/event"
"cosmossdk.io/core/gas"
"cosmossdk.io/core/transaction"
errorsmod "cosmossdk.io/errors"
txsigning "cosmossdk.io/x/tx/signing"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
var (
// simulation signature values used to estimate gas consumption
key = make([]byte, secp256k1.PubKeySize)
simSecp256k1Pubkey = &secp256k1.PubKey{Key: key}
simSecp256k1Sig [64]byte
)
func init() {
// This decodes a valid hex string into a sepc256k1Pubkey for use in transaction simulation
bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A")
copy(key, bz)
simSecp256k1Pubkey.Key = key
}
// SignatureVerificationGasConsumer is the type of function that is used to both
// consume gas when verifying signatures and also to accept or reject different types of pubkeys
// This is where apps can define their own PubKey
type SignatureVerificationGasConsumer = func(meter gas.Meter, sig signing.SignatureV2, params types.Params) error
type AccountAbstractionKeeper interface {
IsAbstractedAccount(ctx context.Context, addr []byte) (bool, error)
AuthenticateAccount(ctx context.Context, signer []byte, bundler string, rawTx *tx.TxRaw, protoTx *tx.Tx, signIndex uint32) error
}
// SigVerificationDecorator verifies all signatures for a tx and returns an
// error if any are invalid.
// It will populate an account's public key if that is not present only if
// PubKey.Address() == Account.Address().
// Note, the SigVerificationDecorator will not check
// signatures on ReCheckTx. It will also increase the sequence number, and consume
// gas for signature verification.
//
// In cases where unordered or parallel transactions are desired, it is recommended
// to set unordered=true with a reasonable timeout_height value, in which case
// this nonce verification and increment will be skipped.
//
// CONTRACT: Tx must implement SigVerifiableTx interface
type SigVerificationDecorator struct {
ak AccountKeeper
aaKeeper AccountAbstractionKeeper
signModeHandler *txsigning.HandlerMap
sigGasConsumer SignatureVerificationGasConsumer
extraVerifyIsOnCurve func(pubKey cryptotypes.PubKey) (bool, error)
}
func NewSigVerificationDecorator(ak AccountKeeper, signModeHandler *txsigning.HandlerMap, sigGasConsumer SignatureVerificationGasConsumer, aaKeeper AccountAbstractionKeeper) SigVerificationDecorator {
return NewSigVerificationDecoratorWithVerifyOnCurve(ak, signModeHandler, sigGasConsumer, aaKeeper, nil)
}
func NewSigVerificationDecoratorWithVerifyOnCurve(ak AccountKeeper, signModeHandler *txsigning.HandlerMap, sigGasConsumer SignatureVerificationGasConsumer, aaKeeper AccountAbstractionKeeper, verifyFn func(pubKey cryptotypes.PubKey) (bool, error)) SigVerificationDecorator {
return SigVerificationDecorator{
aaKeeper: aaKeeper,
ak: ak,
signModeHandler: signModeHandler,
sigGasConsumer: sigGasConsumer,
extraVerifyIsOnCurve: verifyFn,
}
}
// OnlyLegacyAminoSigners checks SignatureData to see if all
// signers are using SIGN_MODE_LEGACY_AMINO_JSON. If this is the case
// then the corresponding SignatureV2 struct will not have account sequence
// explicitly set, and we should skip the explicit verification of sig.Sequence
// in the SigVerificationDecorator's AnteHandler function.
func OnlyLegacyAminoSigners(sigData signing.SignatureData) bool {
switch v := sigData.(type) {
case *signing.SingleSignatureData:
return v.SignMode == signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON
case *signing.MultiSignatureData:
for _, s := range v.Signatures {
if !OnlyLegacyAminoSigners(s) {
return false
}
}
return true
default:
return false
}
}
func (svd SigVerificationDecorator) VerifyIsOnCurve(pubKey cryptotypes.PubKey) error {
if svd.extraVerifyIsOnCurve != nil {
handled, err := svd.extraVerifyIsOnCurve(pubKey)
if handled {
return err
}
}
// when simulating pubKey.Key will always be nil
if pubKey.Bytes() == nil {
return nil
}
switch typedPubKey := pubKey.(type) {
case *secp256k1.PubKey:
pubKeyObject, err := secp256k1dcrd.ParsePubKey(typedPubKey.Bytes())
if err != nil {
if errors.Is(err, secp256k1dcrd.ErrPubKeyNotOnCurve) {
return errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "secp256k1 key is not on curve")
}
return err
}
if !pubKeyObject.IsOnCurve() {
return errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "secp256k1 key is not on curve")
}
case *secp256r1.PubKey:
pubKeyObject := typedPubKey.Key.PublicKey
if !pubKeyObject.IsOnCurve(pubKeyObject.X, pubKeyObject.Y) {
return errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "secp256r1 key is not on curve")
}
case multisig.PubKey:
pubKeysObjects := typedPubKey.GetPubKeys()
ok := true
for _, pubKeyObject := range pubKeysObjects {
if err := svd.VerifyIsOnCurve(pubKeyObject); err != nil {
ok = false
break
}
}
if !ok {
return errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "some keys are not on curve")
}
default:
return errorsmod.Wrapf(sdkerrors.ErrInvalidPubKey, "unsupported key type: %T", typedPubKey)
}
return nil
}
func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if err := svd.ValidateTx(ctx, tx); err != nil {
return ctx, err
}
return next(ctx, tx, false)
}
func (svd SigVerificationDecorator) ValidateTx(ctx context.Context, tx transaction.Tx) error {
sigTx, ok := tx.(authsigning.Tx)
if !ok {
return errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
}
// stdSigs contains the sequence number, account number, and signatures.
// When simulating, this would just be a 0-length slice.
signatures, err := sigTx.GetSignaturesV2()
if err != nil {
return err
}
signers, err := sigTx.GetSigners()
if err != nil {
return err
}
// check that signer length and signature length are the same
if len(signatures) != len(signers) {
return errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signers), len(signatures))
}
pubKeys, err := sigTx.GetPubKeys()
if err != nil {
return err
}
// NOTE: the tx_wrapper implementation returns nil, in case the pubkey is not populated.
// so we can always expect the pubkey of the signer to be at the same index as the signer
// itself. If this does not work, it's a failure in the implementation of the interface.
// we're erroring, but most likely we should be panicking.
if len(pubKeys) != len(signers) {
return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid number of pubkeys; expected %d, got %d", len(signers), len(pubKeys))
}
for i := range signers {
err = svd.authenticate(ctx, sigTx, signers[i], signatures[i], pubKeys[i], i)
if err != nil {
return err
}
}
eventMgr := svd.ak.GetEnvironment().EventService.EventManager(ctx)
events := [][]event.Attribute{}
for i, sig := range signatures {
signerStr, err := svd.ak.AddressCodec().BytesToString(signers[i])
if err != nil {
return err
}
events = append(events, []event.Attribute{event.NewAttribute(sdk.AttributeKeyAccountSequence, fmt.Sprintf("%s/%d", signerStr, sig.Sequence))})
sigBzs, err := signatureDataToBz(sig.Data)
if err != nil {
return err
}
for _, sigBz := range sigBzs {
events = append(events, []event.Attribute{event.NewAttribute(sdk.AttributeKeySignature, base64.StdEncoding.EncodeToString(sigBz))})
}
}
for _, v := range events {
if err := eventMgr.EmitKV(sdk.EventTypeTx, v...); err != nil {
return err
}
}
return nil
}
// authenticate the authentication of the TX for a specific tx signer.
func (svd SigVerificationDecorator) authenticate(ctx context.Context, tx authsigning.Tx, signer []byte, sig signing.SignatureV2, txPubKey cryptotypes.PubKey, signerIndex int) error {
// first we check if it's an AA
if svd.aaKeeper != nil {
isAa, err := svd.aaKeeper.IsAbstractedAccount(ctx, signer)
if err != nil {
return err
}
if isAa {
return svd.authenticateAbstractedAccount(ctx, tx, signer, signerIndex)
}
}
// not an AA, proceed with standard auth flow.
// newlyCreated is a flag that indicates if the account was newly created.
// This is only the case when the user is sending their first tx.
newlyCreated := false
acc := GetSignerAcc(ctx, svd.ak, signer)
if acc == nil {
// If the account is nil, we assume this is the account's first tx. In this case, the account needs to be
// created, but the sign doc should use account number 0. This is because the account number is
// not known until the account is created when the tx was signed, the account number was unknown
// and 0 was set.
acc = svd.ak.NewAccountWithAddress(ctx, txPubKey.Address().Bytes())
newlyCreated = true
}
// the account is without a pubkey, let's attempt to check if in the
// tx we were correctly provided a valid pubkey.
if acc.GetPubKey() == nil {
err := svd.setPubKey(ctx, acc, txPubKey)
if err != nil {
return err
}
}
err := svd.consumeSignatureGas(ctx, acc.GetPubKey(), sig)
if err != nil {
return err
}
err = svd.verifySig(ctx, tx, acc, sig, newlyCreated)
if err != nil {
return err
}
err = svd.increaseSequence(tx, acc)
if err != nil {
return err
}
// update account changes in state.
svd.ak.SetAccount(ctx, acc)
return nil
}
// consumeSignatureGas will consume gas according to the pub-key being verified.
func (svd SigVerificationDecorator) consumeSignatureGas(
ctx context.Context,
pubKey cryptotypes.PubKey,
signature signing.SignatureV2,
) error {
if svd.ak.GetEnvironment().TransactionService.ExecMode(ctx) == transaction.ExecModeSimulate && pubKey == nil {
pubKey = simSecp256k1Pubkey
}
// make a SignatureV2 with PubKey filled in from above
signature = signing.SignatureV2{
PubKey: pubKey,
Data: signature.Data,
Sequence: signature.Sequence,
}
return svd.sigGasConsumer(svd.ak.GetEnvironment().GasService.GasMeter(ctx), signature, svd.ak.GetParams(ctx))
}
// verifySig will verify the signature of the provided signer account.
func (svd SigVerificationDecorator) verifySig(ctx context.Context, tx sdk.Tx, acc sdk.AccountI, sig signing.SignatureV2, newlyCreated bool) error {
execMode := svd.ak.GetEnvironment().TransactionService.ExecMode(ctx)
if execMode == transaction.ExecModeCheck {
if sig.Sequence < acc.GetSequence() {
return errorsmod.Wrapf(
sdkerrors.ErrWrongSequence,
"account sequence mismatch, expected higher than or equal to %d, got %d", acc.GetSequence(), sig.Sequence,
)
}
} else if sig.Sequence != acc.GetSequence() {
return errorsmod.Wrapf(
sdkerrors.ErrWrongSequence,
"account sequence mismatch: expected %d, got %d", acc.GetSequence(), sig.Sequence,
)
}
// we're in simulation mode, or in ReCheckTx, or context is not
// on sig verify tx, then we do not need to verify the signatures
// in the tx.
if execMode == transaction.ExecModeSimulate ||
isRecheckTx(ctx, svd.ak.GetEnvironment().TransactionService) ||
!isSigverifyTx(ctx) {
return nil
}
// retrieve pubkey
pubKey := acc.GetPubKey()
if pubKey == nil {
return errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
}
// retrieve signer data
hinfo := svd.ak.GetEnvironment().HeaderService.HeaderInfo(ctx)
genesis := hinfo.Height == 0
chainID := hinfo.ChainID
var accNum uint64
// if we are not in genesis use the account number from the account
if !genesis {
accNum = acc.GetAccountNumber()
}
// if the account number is 0 and the account is signing, the sign doc will not have an account number
if acc.GetSequence() == 0 && newlyCreated {
// If the account sequence is 0, and we're in genesis, then we're
// dealing with an account that has been generated but never used.
// in this case, we should not verify signatures.
accNum = 0
}
anyPk, _ := codectypes.NewAnyWithValue(pubKey)
signerData := txsigning.SignerData{
Address: acc.GetAddress().String(),
ChainID: chainID,
AccountNumber: accNum,
Sequence: sig.Sequence,
PubKey: &anypb.Any{
TypeUrl: anyPk.TypeUrl,
Value: anyPk.Value,
},
}
adaptableTx, ok := tx.(authsigning.V2AdaptableTx)
if !ok {
return fmt.Errorf("expected tx to implement V2AdaptableTx, got %T", tx)
}
txData := adaptableTx.GetSigningTxData()
err := authsigning.VerifySignature(ctx, pubKey, signerData, sig.Data, svd.signModeHandler, txData)
if err != nil {
var errMsg string
if OnlyLegacyAminoSigners(sig.Data) {
// If all signers are using SIGN_MODE_LEGACY_AMINO, we rely on VerifySignature to check account sequence number,
// and therefore communicate sequence number as a potential cause of error.
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s): (%s)", accNum, acc.GetSequence(), chainID, err.Error())
} else {
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d) and chain-id (%s): (%s)", accNum, chainID, err.Error())
}
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, errMsg)
}
return nil
}
// setPubKey will attempt to set the pubkey for the account given the list of available public keys.
// This must be called only in case the account has not a pubkey set yet.
func (svd SigVerificationDecorator) setPubKey(ctx context.Context, acc sdk.AccountI, txPubKey cryptotypes.PubKey) error {
// if we're not in sig verify then we can just skip.
if !isSigverifyTx(ctx) {
return nil
}
// if the pubkey is nil then we don't have any pubkey to set
// for this account, which also means we cannot do signature
// verification.
if txPubKey == nil {
// if we're not in simulation mode, and we do not have a valid pubkey
// for this signer, then we simply error.
if svd.ak.GetEnvironment().TransactionService.ExecMode(ctx) != transaction.ExecModeSimulate {
return fmt.Errorf("the account %s is without a pubkey and did not provide a pubkey in the tx to set it", acc.GetAddress().String())
}
// if we're in simulation mode, then we can populate the pubkey with the
// sim one and simply return.
txPubKey = simSecp256k1Pubkey
return acc.SetPubKey(txPubKey)
}
// this code path is taken when a user has received tokens but not submitted their first transaction
// if the address does not match the pubkey, then we error.
// TODO: in the future the relationship between address and pubkey should be more flexible.
if !acc.GetAddress().Equals(sdk.AccAddress(txPubKey.Address().Bytes())) {
return sdkerrors.ErrInvalidPubKey.Wrapf("the account %s cannot be claimed by public key with address %x", acc.GetAddress(), txPubKey.Address())
}
err := svd.VerifyIsOnCurve(txPubKey)
if err != nil {
return err
}
// we set the pubkey in the account, without setting it in state.
// this will be done by the increaseSequenceAndUpdateAccount method.
return acc.SetPubKey(txPubKey)
}
// increaseSequence will increase the provided account interface sequence, unless
// the tx is unordered.
func (svd SigVerificationDecorator) increaseSequence(tx authsigning.Tx, acc sdk.AccountI) error {
// Bypass incrementing sequence for transactions with unordered set to true.
// The actual parameters of the un-ordered tx will be checked in a separate
// decorator.
unorderedTx, ok := tx.(sdk.TxWithUnordered)
if ok && unorderedTx.GetUnordered() {
return nil
}
return acc.SetSequence(acc.GetSequence() + 1)
}
// authenticateAbstractedAccount computes an AA authentication instruction and invokes the auth flow on the AA.
func (svd SigVerificationDecorator) authenticateAbstractedAccount(ctx context.Context, authTx authsigning.Tx, signer []byte, index int) error {
// the bundler is the AA itself.
selfBundler, err := svd.ak.AddressCodec().BytesToString(signer)
if err != nil {
return err
}
infoTx := authTx.(interface {
AsTxRaw() (*tx.TxRaw, error)
AsTx() (*tx.Tx, error)
})
txRaw, err := infoTx.AsTxRaw()
if err != nil {
return fmt.Errorf("unable to get raw tx: %w", err)
}
protoTx, err := infoTx.AsTx()
if err != nil {
return fmt.Errorf("unable to get proto tx: %w", err)
}
return svd.aaKeeper.AuthenticateAccount(ctx, signer, selfBundler, txRaw, protoTx, uint32(index))
}
// ValidateSigCountDecorator takes in Params and returns errors if there are too many signatures in the tx for the given params
// otherwise it calls next AnteHandler
// Use this decorator to set parameterized limit on number of signatures in tx
// CONTRACT: Tx must implement SigVerifiableTx interface
type ValidateSigCountDecorator struct {
ak AccountKeeper
}
func NewValidateSigCountDecorator(ak AccountKeeper) ValidateSigCountDecorator {
return ValidateSigCountDecorator{
ak: ak,
}
}
// AnteHandle implements an ante decorator for ValidateSigCountDecorator
func (vscd ValidateSigCountDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if err := vscd.ValidateTx(ctx, tx); err != nil {
return ctx, err
}
return next(ctx, tx, false)
}
// ValidateTx implements an TxValidator for ValidateSigCountDecorator
func (vscd ValidateSigCountDecorator) ValidateTx(ctx context.Context, tx sdk.Tx) error {
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a sigTx")
}
params := vscd.ak.GetParams(ctx)
pubKeys, err := sigTx.GetPubKeys()
if err != nil {
return err
}
sigCount := 0
for _, pk := range pubKeys {
sigCount += CountSubKeys(pk)
if uint64(sigCount) > params.TxSigLimit {
return errorsmod.Wrapf(sdkerrors.ErrTooManySignatures, "signatures: %d, limit: %d", sigCount, params.TxSigLimit)
}
}
return nil
}
// DefaultSigVerificationGasConsumer is the default implementation of SignatureVerificationGasConsumer. It consumes gas
// for signature verification based upon the public key type. The cost is fetched from the given params and is matched
// by the concrete type.
func DefaultSigVerificationGasConsumer(meter gas.Meter, sig signing.SignatureV2, params types.Params) error {
pubkey := sig.PubKey
switch pubkey := pubkey.(type) {
case *ed25519.PubKey:
if err := meter.Consume(params.SigVerifyCostED25519, "ante verify: ed25519"); err != nil {
return err
}
return errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "ED25519 public keys are unsupported")
case *secp256k1.PubKey:
return meter.Consume(params.SigVerifyCostSecp256k1, "ante verify: secp256k1")
case *secp256r1.PubKey:
return meter.Consume(params.SigVerifyCostSecp256r1(), "ante verify: secp256r1")
case multisig.PubKey:
multisignature, ok := sig.Data.(*signing.MultiSignatureData)
if !ok {
return fmt.Errorf("expected %T, got, %T", &signing.MultiSignatureData{}, sig.Data)
}
err := ConsumeMultisignatureVerificationGas(meter, multisignature, pubkey, params, sig.Sequence)
if err != nil {
return err
}
return nil
default:
return errorsmod.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey)
}
}
// ConsumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubKey signature.
func ConsumeMultisignatureVerificationGas(
meter gas.Meter, sig *signing.MultiSignatureData, pubKey multisig.PubKey,
params types.Params, accSeq uint64,
) error {
// if BitArray is nil, it means tx has been built for simulation.
if sig.BitArray == nil {
return multisignatureSimulationVerificationGas(meter, sig, pubKey, params, accSeq)
}
size := sig.BitArray.Count()
sigIndex := 0
for i := 0; i < size; i++ {
if !sig.BitArray.GetIndex(i) {
continue
}
sigV2 := signing.SignatureV2{
PubKey: pubKey.GetPubKeys()[i],
Data: sig.Signatures[sigIndex],
Sequence: accSeq,
}
err := DefaultSigVerificationGasConsumer(meter, sigV2, params)
if err != nil {
return err
}
sigIndex++
}
return nil
}
// multisignatureSimulationVerificationGas consume gas for verifying a simulation multisig pubKey signature. As it's
// a simulation tx the number of signatures its equal to the multisig threshold.
func multisignatureSimulationVerificationGas(
meter gas.Meter, sig *signing.MultiSignatureData, pubKey multisig.PubKey,
params types.Params, accSeq uint64,
) error {
for i := 0; i < len(sig.Signatures); i++ {
sigV2 := signing.SignatureV2{
PubKey: pubKey.GetPubKeys()[i],
Data: sig.Signatures[i],
Sequence: accSeq,
}
err := DefaultSigVerificationGasConsumer(meter, sigV2, params)
if err != nil {
return err
}
}
return nil
}
// GetSignerAcc returns an account for a given address that is expected to sign
// a transaction.
func GetSignerAcc(ctx context.Context, ak AccountKeeper, addr sdk.AccAddress) sdk.AccountI {
return ak.GetAccount(ctx, addr)
}
// CountSubKeys counts the total number of keys for a multi-sig public key.
// A non-multisig, i.e. a regular signature, it naturally a count of 1. If it is a multisig,
// then it recursively calls it on its pubkeys.
func CountSubKeys(pub cryptotypes.PubKey) int {
if pub == nil {
return 0
}
v, ok := pub.(*kmultisig.LegacyAminoPubKey)
if !ok {
return 1
}
numKeys := 0
for _, subkey := range v.GetPubKeys() {
numKeys += CountSubKeys(subkey)
}
return numKeys
}
// signatureDataToBz converts a SignatureData into raw bytes signature.
// For SingleSignatureData, it returns the signature raw bytes.
// For MultiSignatureData, it returns an array of all individual signatures,
// as well as the aggregated signature.
func signatureDataToBz(data signing.SignatureData) ([][]byte, error) {
if data == nil {
return nil, errors.New("got empty SignatureData")
}
switch data := data.(type) {
case *signing.SingleSignatureData:
return [][]byte{data.Signature}, nil
case *signing.MultiSignatureData:
sigs := [][]byte{}
var err error
for _, d := range data.Signatures {
nestedSigs, err := signatureDataToBz(d)
if err != nil {
return nil, err
}
sigs = append(sigs, nestedSigs...)
}
multiSignature := cryptotypes.MultiSignature{
Signatures: sigs,
}
aggregatedSig, err := multiSignature.Marshal()
if err != nil {
return nil, err
}
sigs = append(sigs, aggregatedSig)
return sigs, nil
default:
return nil, sdkerrors.ErrInvalidType.Wrapf("unexpected signature data type %T", data)
}
}
// isSigverifyTx will always return true, unless the context is a sdk.Context, in which case we will return the
// value of IsSigverifyTx.
func isSigverifyTx(ctx context.Context) bool {
if sdkCtx, ok := sdk.TryUnwrapSDKContext(ctx); ok {
return sdkCtx.IsSigverifyTx()
}
return true
}
func isRecheckTx(ctx context.Context, txSvc transaction.Service) bool {
if sdkCtx, ok := sdk.TryUnwrapSDKContext(ctx); ok {
return sdkCtx.IsReCheckTx()
}
return txSvc.ExecMode(ctx) == transaction.ExecModeReCheck
}