Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(x/auth): allow multiple = signs in GetTxsEvent #12474

Merged
merged 4 commits into from
Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions x/auth/tx/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tx
import (
"context"
"fmt"
"regexp"
"strings"

gogogrpc "github.com/gogo/protobuf/grpc"
Expand Down Expand Up @@ -39,13 +40,18 @@ func NewTxServer(clientCtx client.Context, simulate baseAppSimulateFn, interface
}
}

var _ txtypes.ServiceServer = txServer{}
var (
_ txtypes.ServiceServer = txServer{}

// EventRegex checks that an event string is formatted with {alphabetic}.{alphabetic}={value}
EventRegex = regexp.MustCompile(`^[a-zA-Z]+\.[a-zA-Z]+=\S+$`)

This comment was marked as resolved.

Copy link
Member

@julienrbrt julienrbrt Jul 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was indeed a regression, but it has been resolved in #16994, and is included in v0.46.14 and v0.47.4.
The Cosmos Hub still uses the deprecated SDK version v0.45.x and this fix wasn't backported there at the first place.

)

const (
eventFormat = "{eventType}.{eventAttribute}={value}"
)

// TxsByEvents implements the ServiceServer.TxsByEvents RPC method.
// GetTxsEvent implements the ServiceServer.TxsByEvents RPC method.
func (s txServer) GetTxsEvent(ctx context.Context, req *txtypes.GetTxsEventRequest) (*txtypes.GetTxsEventResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "request cannot be nil")
Expand All @@ -69,7 +75,7 @@ func (s txServer) GetTxsEvent(ctx context.Context, req *txtypes.GetTxsEventReque
}

for _, event := range req.Events {
if !strings.Contains(event, "=") || strings.Count(event, "=") > 1 {
if !EventRegex.Match([]byte(event)) {
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid event; event %s should be of the format: %s", event, eventFormat))
}
}
Expand Down
75 changes: 75 additions & 0 deletions x/auth/tx/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ package tx_test

import (
"context"
"encoding/base64"
"fmt"
"strings"
"testing"

"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"

"github.com/cosmos/cosmos-sdk/client"
Expand All @@ -28,6 +30,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authtest "github.com/cosmos/cosmos-sdk/x/auth/client/testutil"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
Expand Down Expand Up @@ -111,6 +114,78 @@ func (s *IntegrationTestSuite) TearDownSuite() {
s.network.Cleanup()
}

func (s *IntegrationTestSuite) TestQueryBySig() {
// broadcast tx
txb := s.mkTxBuilder()
txbz, err := s.cfg.TxConfig.TxEncoder()(txb.GetTx())
s.Require().NoError(err)
_, err = s.queryClient.BroadcastTx(context.Background(), &tx.BroadcastTxRequest{TxBytes: txbz, Mode: tx.BroadcastMode_BROADCAST_MODE_BLOCK})
s.Require().NoError(err)

// get the signature out of the builder
sigs, err := txb.GetTx().GetSignaturesV2()
s.Require().NoError(err)
s.Require().Len(sigs, 1)
sig, ok := sigs[0].Data.(*signing.SingleSignatureData)
s.Require().True(ok)

// encode, format, query
b64Sig := base64.StdEncoding.EncodeToString(sig.Signature)
sigFormatted := fmt.Sprintf("%s.%s='%s'", sdk.EventTypeTx, sdk.AttributeKeySignature, b64Sig)
res, err := s.queryClient.GetTxsEvent(context.Background(), &tx.GetTxsEventRequest{
Events: []string{sigFormatted},
OrderBy: 0,
Page: 0,
Limit: 10,
})
s.Require().NoError(err)
s.Require().Len(res.Txs, 1)
s.Require().Len(res.Txs[0].Signatures, 1)
s.Require().Equal(res.Txs[0].Signatures[0], sig.Signature)

// bad format should error
_, err = s.queryClient.GetTxsEvent(context.Background(), &tx.GetTxsEventRequest{Events: []string{"tx.foo.bar='baz'"}})
s.Require().ErrorContains(err, "invalid event;")
}

func TestEventRegex(t *testing.T) {
t.Parallel()

testCases := []struct {
name string
event string
match bool
}{
{
name: "valid: with quotes",
event: "tx.message='something'",
match: true,
},
{
name: "valid: no quotes",
event: "tx.message=something",
match: true,
},
{
name: "invalid: too many separators",
event: "tx.message.foo='bar'",
match: false,
},
{
name: "valid: symbols ok",
event: "tx.signature='foobar/baz123=='",
match: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
match := authtx.EventRegex.Match([]byte(tc.event))
require.Equal(t, tc.match, match)
})
}
}

func (s IntegrationTestSuite) TestSimulateTx_GRPC() {
val := s.network.Validators[0]
txBuilder := s.mkTxBuilder()
Expand Down