Skip to content

Commit

Permalink
feat: add sign mode direct aux handler (cosmos#9944)
Browse files Browse the repository at this point in the history
<!--
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: cosmos#9911 

<!-- 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)
  • Loading branch information
atheeshp authored Sep 14, 2021
1 parent acf823d commit cb5bfb7
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 0 deletions.
15 changes: 15 additions & 0 deletions client/tx/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions x/auth/signing/sign_mode_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
52 changes: 52 additions & 0 deletions x/auth/tx/direct_aux.go
Original file line number Diff line number Diff line change
@@ -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()
}
140 changes: 140 additions & 0 deletions x/auth/tx/direct_aux_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
2 changes: 2 additions & 0 deletions x/auth/tx/mode_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
Expand Down

0 comments on commit cb5bfb7

Please sign in to comment.