cosmos-sdk/x/auth/testutil/suite.go
Amaury b6f1972ebc
refactor: Change SignerData.SignerIndex to PubKey (#10692)
<!--
The default pull request template is for types feat, fix, or refactor.
For other templates, add one of the following parameters to the url:
- template=docs.md
- template=other.md
-->

## Description

Closes: #10691 

<!-- Add a description of the changes that this PR introduces and the files that
are the most critical to review. -->

---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
2021-12-08 11:43:15 +00:00

310 lines
9.6 KiB
Go

package testutil
import (
"bytes"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client"
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
)
// TxConfigTestSuite provides a test suite that can be used to test that a TxConfig implementation is correct.
type TxConfigTestSuite struct {
suite.Suite
TxConfig client.TxConfig
}
// NewTxConfigTestSuite returns a new TxConfigTestSuite with the provided TxConfig implementation
func NewTxConfigTestSuite(txConfig client.TxConfig) *TxConfigTestSuite {
return &TxConfigTestSuite{TxConfig: txConfig}
}
func (s *TxConfigTestSuite) TestTxBuilderGetTx() {
txBuilder := s.TxConfig.NewTxBuilder()
tx := txBuilder.GetTx()
s.Require().NotNil(tx)
s.Require().Equal(len(tx.GetMsgs()), 0)
}
func (s *TxConfigTestSuite) TestTxBuilderSetFeeAmount() {
txBuilder := s.TxConfig.NewTxBuilder()
feeAmount := sdk.Coins{
sdk.NewInt64Coin("atom", 20000000),
}
txBuilder.SetFeeAmount(feeAmount)
feeTx := txBuilder.GetTx()
s.Require().Equal(feeAmount, feeTx.GetFee())
}
func (s *TxConfigTestSuite) TestTxBuilderSetGasLimit() {
const newGas uint64 = 300000
txBuilder := s.TxConfig.NewTxBuilder()
txBuilder.SetGasLimit(newGas)
feeTx := txBuilder.GetTx()
s.Require().Equal(newGas, feeTx.GetGas())
}
func (s *TxConfigTestSuite) TestTxBuilderSetMemo() {
const newMemo string = "newfoomemo"
txBuilder := s.TxConfig.NewTxBuilder()
txBuilder.SetMemo(newMemo)
txWithMemo := txBuilder.GetTx()
s.Require().Equal(txWithMemo.GetMemo(), newMemo)
}
func (s *TxConfigTestSuite) TestTxBuilderSetMsgs() {
_, _, addr1 := testdata.KeyTestPubAddr()
_, _, addr2 := testdata.KeyTestPubAddr()
msg1 := testdata.NewTestMsg(addr1)
msg2 := testdata.NewTestMsg(addr2)
msgs := []sdk.Msg{msg1, msg2}
txBuilder := s.TxConfig.NewTxBuilder()
err := txBuilder.SetMsgs(msgs...)
s.Require().NoError(err)
tx := txBuilder.GetTx()
s.Require().Equal(msgs, tx.GetMsgs())
s.Require().Equal([]sdk.AccAddress{addr1, addr2}, tx.GetSigners())
s.Require().Equal(addr1, tx.FeePayer())
s.Require().Error(tx.ValidateBasic()) // should fail because of no signatures
}
func (s *TxConfigTestSuite) TestTxBuilderSetSignatures() {
privKey, pubkey, addr := testdata.KeyTestPubAddr()
privKey2, pubkey2, _ := testdata.KeyTestPubAddr()
multisigPk := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{pubkey, pubkey2})
txBuilder := s.TxConfig.NewTxBuilder()
// set test msg
msg := testdata.NewTestMsg(addr)
msigAddr := sdk.AccAddress(multisigPk.Address())
msg2 := testdata.NewTestMsg(msigAddr)
err := txBuilder.SetMsgs(msg, msg2)
txBuilder.SetFeeAmount(testdata.NewTestFeeAmount())
s.Require().NoError(err)
// check that validation fails
s.Require().Error(txBuilder.GetTx().ValidateBasic())
signModeHandler := s.TxConfig.SignModeHandler()
s.Require().Contains(signModeHandler.Modes(), signModeHandler.DefaultMode())
// set SignatureV2 without actual signature bytes
seq1 := uint64(2) // Arbitrary account sequence
sigData1 := &signingtypes.SingleSignatureData{SignMode: signModeHandler.DefaultMode()}
sig1 := signingtypes.SignatureV2{PubKey: pubkey, Data: sigData1, Sequence: seq1}
mseq := uint64(4) // Arbitrary account sequence
msigData := multisig.NewMultisig(2)
multisig.AddSignature(msigData, &signingtypes.SingleSignatureData{SignMode: signModeHandler.DefaultMode()}, 0)
multisig.AddSignature(msigData, &signingtypes.SingleSignatureData{SignMode: signModeHandler.DefaultMode()}, 1)
msig := signingtypes.SignatureV2{PubKey: multisigPk, Data: msigData, Sequence: mseq}
// fail validation without required signers
err = txBuilder.SetSignatures(sig1)
s.Require().NoError(err)
sigTx := txBuilder.GetTx()
s.Require().Error(sigTx.ValidateBasic())
err = txBuilder.SetSignatures(sig1, msig)
s.Require().NoError(err)
sigTx = txBuilder.GetTx()
sigsV2, err := sigTx.GetSignaturesV2()
s.Require().NoError(err)
s.Require().Len(sigsV2, 2)
s.Require().True(sigEquals(sig1, sigsV2[0]))
s.Require().True(sigEquals(msig, sigsV2[1]))
s.Require().Equal([]sdk.AccAddress{addr, msigAddr}, sigTx.GetSigners())
s.Require().NoError(sigTx.ValidateBasic())
// sign transaction
signerData := signing.SignerData{
Address: addr.String(),
ChainID: "test",
AccountNumber: 1,
Sequence: seq1,
PubKey: pubkey,
}
signBytes, err := signModeHandler.GetSignBytes(signModeHandler.DefaultMode(), signerData, sigTx)
s.Require().NoError(err)
sigBz, err := privKey.Sign(signBytes)
s.Require().NoError(err)
signerData = signing.SignerData{
Address: msigAddr.String(),
ChainID: "test",
AccountNumber: 3,
Sequence: mseq,
PubKey: multisigPk,
}
mSignBytes, err := signModeHandler.GetSignBytes(signModeHandler.DefaultMode(), signerData, sigTx)
s.Require().NoError(err)
mSigBz1, err := privKey.Sign(mSignBytes)
s.Require().NoError(err)
mSigBz2, err := privKey2.Sign(mSignBytes)
s.Require().NoError(err)
msigData = multisig.NewMultisig(2)
multisig.AddSignature(msigData, &signingtypes.SingleSignatureData{
SignMode: signModeHandler.DefaultMode(), Signature: mSigBz1}, 0)
multisig.AddSignature(msigData, &signingtypes.SingleSignatureData{
SignMode: signModeHandler.DefaultMode(), Signature: mSigBz2}, 0)
// set signature
sigData1.Signature = sigBz
sig1 = signingtypes.SignatureV2{PubKey: pubkey, Data: sigData1, Sequence: seq1}
msig = signingtypes.SignatureV2{PubKey: multisigPk, Data: msigData, Sequence: mseq}
err = txBuilder.SetSignatures(sig1, msig)
s.Require().NoError(err)
sigTx = txBuilder.GetTx()
sigsV2, err = sigTx.GetSignaturesV2()
s.Require().NoError(err)
s.Require().Len(sigsV2, 2)
s.Require().True(sigEquals(sig1, sigsV2[0]))
s.Require().True(sigEquals(msig, sigsV2[1]))
s.Require().Equal([]sdk.AccAddress{addr, msigAddr}, sigTx.GetSigners())
s.Require().NoError(sigTx.ValidateBasic())
}
func sigEquals(sig1, sig2 signingtypes.SignatureV2) bool {
if !sig1.PubKey.Equals(sig2.PubKey) {
return false
}
if sig1.Data == nil && sig2.Data == nil {
return true
}
return sigDataEquals(sig1.Data, sig2.Data)
}
func sigDataEquals(data1, data2 signingtypes.SignatureData) bool {
switch data1 := data1.(type) {
case *signingtypes.SingleSignatureData:
data2, ok := data2.(*signingtypes.SingleSignatureData)
if !ok {
return false
}
if data1.SignMode != data2.SignMode {
return false
}
return bytes.Equal(data1.Signature, data2.Signature)
case *signingtypes.MultiSignatureData:
data2, ok := data2.(*signingtypes.MultiSignatureData)
if !ok {
return false
}
if !data1.BitArray.Equal(data2.BitArray) || len(data1.Signatures) != len(data2.Signatures) {
return false
}
for i, s := range data1.Signatures {
if !sigDataEquals(s, data2.Signatures[i]) {
return false
}
}
return true
default:
return false
}
}
func (s *TxConfigTestSuite) TestTxEncodeDecode() {
log := s.T().Log
_, pubkey, addr := testdata.KeyTestPubAddr()
feeAmount := sdk.Coins{sdk.NewInt64Coin("atom", 150)}
gasLimit := uint64(50000)
memo := "foomemo"
msg := testdata.NewTestMsg(addr)
dummySig := []byte("dummySig")
sig := signingtypes.SignatureV2{
PubKey: pubkey,
Data: &signingtypes.SingleSignatureData{
SignMode: signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
Signature: dummySig,
},
}
txBuilder := s.TxConfig.NewTxBuilder()
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(gasLimit)
txBuilder.SetMemo(memo)
err := txBuilder.SetMsgs(msg)
s.Require().NoError(err)
err = txBuilder.SetSignatures(sig)
s.Require().NoError(err)
tx := txBuilder.GetTx()
log("encode transaction")
txBytes, err := s.TxConfig.TxEncoder()(tx)
s.Require().NoError(err)
s.Require().NotNil(txBytes)
log("decode transaction", s.TxConfig)
tx2, err := s.TxConfig.TxDecoder()(txBytes)
s.Require().NoError(err)
tx3, ok := tx2.(signing.Tx)
s.Require().True(ok)
s.Require().Equal([]sdk.Msg{msg}, tx3.GetMsgs())
s.Require().Equal(feeAmount, tx3.GetFee())
s.Require().Equal(gasLimit, tx3.GetGas())
s.Require().Equal(memo, tx3.GetMemo())
tx3Sigs, err := tx3.GetSignaturesV2()
s.Require().NoError(err)
s.Require().Equal([]signingtypes.SignatureV2{sig}, tx3Sigs)
pks, err := tx3.GetPubKeys()
s.Require().NoError(err)
s.Require().Equal([]cryptotypes.PubKey{pubkey}, pks)
log("JSON encode transaction")
jsonTxBytes, err := s.TxConfig.TxJSONEncoder()(tx)
s.Require().NoError(err)
s.Require().NotNil(jsonTxBytes)
log("JSON decode transaction")
tx2, err = s.TxConfig.TxJSONDecoder()(jsonTxBytes)
s.Require().NoError(err)
tx3, ok = tx2.(signing.Tx)
s.Require().True(ok)
s.Require().Equal([]sdk.Msg{msg}, tx3.GetMsgs())
s.Require().Equal(feeAmount, tx3.GetFee())
s.Require().Equal(gasLimit, tx3.GetGas())
s.Require().Equal(memo, tx3.GetMemo())
tx3Sigs, err = tx3.GetSignaturesV2()
s.Require().NoError(err)
s.Require().Equal([]signingtypes.SignatureV2{sig}, tx3Sigs)
pks, err = tx3.GetPubKeys()
s.Require().NoError(err)
s.Require().Equal([]cryptotypes.PubKey{pubkey}, pks)
}
func (s *TxConfigTestSuite) TestWrapTxBuilder() {
_, _, addr := testdata.KeyTestPubAddr()
feeAmount := sdk.Coins{sdk.NewInt64Coin("atom", 150)}
gasLimit := uint64(50000)
memo := "foomemo"
msg := testdata.NewTestMsg(addr)
txBuilder := s.TxConfig.NewTxBuilder()
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(gasLimit)
txBuilder.SetMemo(memo)
err := txBuilder.SetMsgs(msg)
s.Require().NoError(err)
newTxBldr, err := s.TxConfig.WrapTxBuilder(txBuilder.GetTx())
s.Require().NoError(err)
s.Require().Equal(txBuilder, newTxBldr)
}