From cb5bfb7678985142b79150c03ca99694fe3ff46c Mon Sep 17 00:00:00 2001 From: atheeshp <59333759+atheeshp@users.noreply.github.com> Date: Tue, 14 Sep 2021 15:12:42 +0530 Subject: [PATCH] feat: add sign mode direct aux handler (#9944) ## Description Closes: #9911 --- ### 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) --- client/tx/tx.go | 15 +++ x/auth/signing/sign_mode_handler.go | 3 + x/auth/tx/direct_aux.go | 52 +++++++++++ x/auth/tx/direct_aux_test.go | 140 ++++++++++++++++++++++++++++ x/auth/tx/mode_handler.go | 2 + 5 files changed, 212 insertions(+) create mode 100644 x/auth/tx/direct_aux.go create mode 100644 x/auth/tx/direct_aux_test.go diff --git a/client/tx/tx.go b/client/tx/tx.go index 4adaaa0e1c..d98eb7a4f0 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -201,11 +201,26 @@ func Sign(txf Factory, name string, txBuilder client.TxBuilder, overwriteSig boo if err != nil { return err } + pubKey := key.GetPubKey() + pubkeys, err := txBuilder.GetTx().GetPubKeys() + if err != nil { + return err + } + + signerIndex := 0 + for i, p := range pubkeys { + if p.Equals(pubKey) { + signerIndex = i + break + } + } + signerData := authsigning.SignerData{ ChainID: txf.chainID, AccountNumber: txf.accountNumber, Sequence: txf.sequence, + SignerIndex: signerIndex, } // For SIGN_MODE_DIRECT, calling SetSignatures calls setSignerInfos on diff --git a/x/auth/signing/sign_mode_handler.go b/x/auth/signing/sign_mode_handler.go index e70246ee27..cf82b3f66d 100644 --- a/x/auth/signing/sign_mode_handler.go +++ b/x/auth/signing/sign_mode_handler.go @@ -34,4 +34,7 @@ type SignerData struct { // since in SIGN_MODE_DIRECT the account sequence is already in the signer // info. Sequence uint64 + + // SignerIndex index of signer in the signer_infos array + SignerIndex int } diff --git a/x/auth/tx/direct_aux.go b/x/auth/tx/direct_aux.go new file mode 100644 index 0000000000..cf66859679 --- /dev/null +++ b/x/auth/tx/direct_aux.go @@ -0,0 +1,52 @@ +package tx + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types/tx" + signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" + + "github.com/cosmos/cosmos-sdk/x/auth/signing" +) + +var _ signing.SignModeHandler = signModeDirectAuxHandler{} + +// signModeDirectAuxHandler defines the SIGN_MODE_DIRECT_AUX SignModeHandler +type signModeDirectAuxHandler struct{} + +// DefaultMode implements SignModeHandler.DefaultMode +func (signModeDirectAuxHandler) DefaultMode() signingtypes.SignMode { + return signingtypes.SignMode_SIGN_MODE_DIRECT_AUX +} + +// Modes implements SignModeHandler.Modes +func (signModeDirectAuxHandler) Modes() []signingtypes.SignMode { + return []signingtypes.SignMode{signingtypes.SignMode_SIGN_MODE_DIRECT_AUX} +} + +// GetSignBytes implements SignModeHandler.GetSignBytes +func (signModeDirectAuxHandler) GetSignBytes( + mode signingtypes.SignMode, data signing.SignerData, tx sdk.Tx, +) ([]byte, error) { + + if mode != signingtypes.SignMode_SIGN_MODE_DIRECT_AUX { + return nil, fmt.Errorf("expected %s, got %s", signingtypes.SignMode_SIGN_MODE_DIRECT_AUX, mode) + } + + protoTx, ok := tx.(*wrapper) + if !ok { + return nil, fmt.Errorf("can only handle a protobuf Tx, got %T", tx) + } + + signDocDirectAux := types.SignDocDirectAux{ + BodyBytes: protoTx.getBodyBytes(), + ChainId: data.ChainID, + AccountNumber: data.AccountNumber, + Sequence: data.Sequence, + Tip: protoTx.tx.AuthInfo.Tip, + PublicKey: protoTx.tx.AuthInfo.SignerInfos[data.SignerIndex].PublicKey, + } + + return signDocDirectAux.Marshal() +} diff --git a/x/auth/tx/direct_aux_test.go b/x/auth/tx/direct_aux_test.go new file mode 100644 index 0000000000..777d97accb --- /dev/null +++ b/x/auth/tx/direct_aux_test.go @@ -0,0 +1,140 @@ +package tx + +import ( + "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + txtypes "github.com/cosmos/cosmos-sdk/types/tx" + signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" + "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/stretchr/testify/require" +) + +func TestDirectAuxHandler(t *testing.T) { + privKey, pubkey, addr := testdata.KeyTestPubAddr() + interfaceRegistry := codectypes.NewInterfaceRegistry() + interfaceRegistry.RegisterImplementations((*sdk.Msg)(nil), &testdata.TestMsg{}) + marshaler := codec.NewProtoCodec(interfaceRegistry) + + txConfig := NewTxConfig(marshaler, []signingtypes.SignMode{signingtypes.SignMode_SIGN_MODE_DIRECT_AUX}) + txBuilder := txConfig.NewTxBuilder() + + memo := "sometestmemo" + msgs := []sdk.Msg{testdata.NewTestMsg(addr)} + accSeq := uint64(2) // Arbitrary account sequence + + any, err := codectypes.NewAnyWithValue(pubkey) + require.NoError(t, err) + + sigData := &signingtypes.SingleSignatureData{ + SignMode: signingtypes.SignMode_SIGN_MODE_DIRECT_AUX, + } + + sig := signingtypes.SignatureV2{ + PubKey: pubkey, + Data: sigData, + Sequence: accSeq, + } + + fee := txtypes.Fee{Amount: sdk.NewCoins(sdk.NewInt64Coin("atom", 150)), GasLimit: 20000} + + err = txBuilder.SetMsgs(msgs...) + require.NoError(t, err) + txBuilder.SetMemo(memo) + txBuilder.SetFeeAmount(fee.Amount) + txBuilder.SetGasLimit(fee.GasLimit) + + err = txBuilder.SetSignatures(sig) + require.NoError(t, err) + + signingData := signing.SignerData{ + ChainID: "test-chain", + AccountNumber: 1, + } + + modeHandler := signModeDirectAuxHandler{} + signBytes, err := modeHandler.GetSignBytes(signingtypes.SignMode_SIGN_MODE_DIRECT_AUX, signingData, txBuilder.GetTx()) + require.NoError(t, err) + require.NotNil(t, signBytes) + + anys := make([]*codectypes.Any, len(msgs)) + for i, msg := range msgs { + var err error + anys[i], err = codectypes.NewAnyWithValue(msg) + if err != nil { + panic(err) + } + } + + txBody := &txtypes.TxBody{ + Memo: memo, + Messages: anys, + } + bodyBytes := marshaler.MustMarshal(txBody) + + t.Log("verify GetSignBytes with generating sign bytes by marshaling signDocDirectAux") + signDocDirectAux := txtypes.SignDocDirectAux{ + AccountNumber: 1, + BodyBytes: bodyBytes, + ChainId: "test-chain", + PublicKey: any, + } + + expectedSignBytes, err := signDocDirectAux.Marshal() + require.NoError(t, err) + require.Equal(t, expectedSignBytes, signBytes) + + t.Log("verify that setting signature doesn't change sign bytes") + sigData.Signature, err = privKey.Sign(signBytes) + require.NoError(t, err) + err = txBuilder.SetSignatures(sig) + require.NoError(t, err) + signBytes, err = modeHandler.GetSignBytes(signingtypes.SignMode_SIGN_MODE_DIRECT_AUX, signingData, txBuilder.GetTx()) + require.NoError(t, err) + require.Equal(t, expectedSignBytes, signBytes) + + t.Log("verify GetSignBytes with false txBody data") + signDocDirectAux.BodyBytes = []byte("dfafdasfds") + expectedSignBytes, err = signDocDirectAux.Marshal() + require.NoError(t, err) + require.NotEqual(t, expectedSignBytes, signBytes) +} + +func TestDirectAuxHandler_DefaultMode(t *testing.T) { + handler := signModeDirectAuxHandler{} + require.Equal(t, signingtypes.SignMode_SIGN_MODE_DIRECT_AUX, handler.DefaultMode()) +} + +func TestDirectAuxModeHandler_nonDIRECT_MODE(t *testing.T) { + invalidModes := []signingtypes.SignMode{ + signingtypes.SignMode_SIGN_MODE_DIRECT, + signingtypes.SignMode_SIGN_MODE_DIRECT_JSON, + signingtypes.SignMode_SIGN_MODE_TEXTUAL, + signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, + signingtypes.SignMode_SIGN_MODE_UNSPECIFIED, + } + for _, invalidMode := range invalidModes { + t.Run(invalidMode.String(), func(t *testing.T) { + var dh signModeDirectAuxHandler + var signingData signing.SignerData + _, err := dh.GetSignBytes(invalidMode, signingData, nil) + require.Error(t, err) + wantErr := fmt.Errorf("expected %s, got %s", signingtypes.SignMode_SIGN_MODE_DIRECT_AUX, invalidMode) + require.Equal(t, err, wantErr) + }) + } +} + +func TestDirectAuxModeHandler_nonProtoTx(t *testing.T) { + var dh signModeDirectAuxHandler + var signingData signing.SignerData + tx := new(nonProtoTx) + _, err := dh.GetSignBytes(signingtypes.SignMode_SIGN_MODE_DIRECT_AUX, signingData, tx) + require.Error(t, err) + wantErr := fmt.Errorf("can only handle a protobuf Tx, got %T", tx) + require.Equal(t, err, wantErr) +} diff --git a/x/auth/tx/mode_handler.go b/x/auth/tx/mode_handler.go index f49ee16198..3a9b17df8f 100644 --- a/x/auth/tx/mode_handler.go +++ b/x/auth/tx/mode_handler.go @@ -28,6 +28,8 @@ func makeSignModeHandler(modes []signingtypes.SignMode) signing.SignModeHandler handlers[i] = signModeDirectHandler{} case signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON: handlers[i] = signModeLegacyAminoJSONHandler{} + case signingtypes.SignMode_SIGN_MODE_DIRECT_AUX: + handlers[i] = signModeDirectAuxHandler{} default: panic(fmt.Errorf("unsupported sign mode %+v", mode)) }