diff --git a/CHANGELOG.md b/CHANGELOG.md index c4b5a5e24ef6..3967d6d2b38c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -222,6 +222,15 @@ Ref: https://keepachangelog.com/en/1.0.0/ * The field `OperationMsg.Msg` is now of type `[]byte` instead of `json.RawMessage`. * (cli) [#16209](https://github.com/cosmos/cosmos-sdk/pull/16209) Add API `StartCmdWithOptions` to create customized start command. * (x/distribution) [#16211](https://github.com/cosmos/cosmos-sdk/pull/16211) Use collections for params state management. +* [#15284](https://github.com/cosmos/cosmos-sdk/pull/15284) + * `sdk.Msg.GetSigners` was deprecated and is no longer supported. Use the `cosmos.msg.v1.signer` protobuf annotation instead. + * `sdk.Tx` now requires a new method `GetMsgsV2()`. + * `types/tx.Tx` no longer implements `sdk.Tx`. + * `TxConfig` has a new method `SigningContext() *signing.Context`. + * `AccountKeeper` now has an `AddressCodec() address.Codec` method and the expected `AccountKeeper` for `x/auth/ante` expects this method. + * `SigVerifiableTx.GetSigners()` now returns `([][]byte, error)` instead of `[]sdk.AccAddress`. +* (x/authx) [#15284](https://github.com/cosmos/cosmos-sdk/pull/15284) `NewKeeper` now requires `codec.Codec`. +* (x/gov) [#15284](https://github.com/cosmos/cosmos-sdk/pull/15284) `NewKeeper` now requires `codec.Codec`. ### Client Breaking Changes diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 7779b0a786cf..9d12ed1ac121 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -10,16 +10,18 @@ import ( errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" - pruningtypes "cosmossdk.io/store/pruning/types" - "cosmossdk.io/store/snapshots" - snapshottypes "cosmossdk.io/store/snapshots/types" - storetypes "cosmossdk.io/store/types" + abci "github.com/cometbft/cometbft/abci/types" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/jsonpb" "github.com/stretchr/testify/require" + pruningtypes "cosmossdk.io/store/pruning/types" + "cosmossdk.io/store/snapshots" + snapshottypes "cosmossdk.io/store/snapshots/types" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/baseapp" baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil" "github.com/cosmos/cosmos-sdk/testutil" @@ -455,8 +457,9 @@ func TestABCI_FinalizeBlock_MultiMsg(t *testing.T) { builder := suite.txConfig.NewTxBuilder() msgs := tx.GetMsgs() - msgs = append(msgs, &baseapptestutil.MsgCounter2{Counter: 0}) - msgs = append(msgs, &baseapptestutil.MsgCounter2{Counter: 1}) + _, _, addr := testdata.KeyTestPubAddr() + msgs = append(msgs, &baseapptestutil.MsgCounter2{Counter: 0, Signer: addr.String()}) + msgs = append(msgs, &baseapptestutil.MsgCounter2{Counter: 1, Signer: addr.String()}) builder.SetMsgs(msgs...) builder.SetMemo(tx.GetMemo()) @@ -611,7 +614,8 @@ func TestABCI_InvalidTransaction(t *testing.T) { // transaction with no known route { txBuilder := suite.txConfig.NewTxBuilder() - txBuilder.SetMsgs(&baseapptestutil.MsgCounter2{}) + _, _, addr := testdata.KeyTestPubAddr() + txBuilder.SetMsgs(&baseapptestutil.MsgCounter2{Signer: addr.String()}) setTxSignature(t, txBuilder, 0) unknownRouteTx := txBuilder.GetTx() @@ -624,7 +628,10 @@ func TestABCI_InvalidTransaction(t *testing.T) { require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), code, err) txBuilder = suite.txConfig.NewTxBuilder() - txBuilder.SetMsgs(&baseapptestutil.MsgCounter{}, &baseapptestutil.MsgCounter2{}) + txBuilder.SetMsgs( + &baseapptestutil.MsgCounter{Signer: addr.String()}, + &baseapptestutil.MsgCounter2{Signer: addr.String()}, + ) setTxSignature(t, txBuilder, 0) unknownRouteTx = txBuilder.GetTx() @@ -1247,7 +1254,7 @@ func TestABCI_PrepareProposal_ReachedMaxBytes(t *testing.T) { } resPrepareProposal, err := suite.baseApp.PrepareProposal(&reqPrepareProposal) require.NoError(t, err) - require.Equal(t, 11, len(resPrepareProposal.Txs)) + require.Equal(t, 8, len(resPrepareProposal.Txs)) } func TestABCI_PrepareProposal_BadEncoding(t *testing.T) { diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 1890ef510363..5e548dc77bb6 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -8,10 +8,6 @@ import ( errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" - "cosmossdk.io/store" - storemetrics "cosmossdk.io/store/metrics" - "cosmossdk.io/store/snapshots" - storetypes "cosmossdk.io/store/types" "github.com/cockroachdb/errors" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto/tmhash" @@ -19,7 +15,14 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/proto" "golang.org/x/exp/maps" + protov2 "google.golang.org/protobuf/proto" + + "cosmossdk.io/store" + storemetrics "cosmossdk.io/store/metrics" + "cosmossdk.io/store/snapshots" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/telemetry" @@ -174,6 +177,8 @@ type BaseApp struct { streamingManager storetypes.StreamingManager chainID string + + cdc codec.Codec } // NewBaseApp returns a reference to an initialized BaseApp. It accepts a @@ -222,6 +227,10 @@ func NewBaseApp( app.runTxRecoveryMiddleware = newDefaultRecoveryMiddleware() + // Initialize with an empty interface registry to avoid nil pointer dereference. + // Unless SetInterfaceRegistry is called with an interface registry with proper address codecs base app will panic. + app.cdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + return app } @@ -636,7 +645,7 @@ func (app *BaseApp) getContextForTx(mode execMode, txBytes []byte) sdk.Context { } ctx := modeState.ctx. WithTxBytes(txBytes) - // WithVoteInfos(app.voteInfos) // TODO: identify if this is needed + // WithVoteInfos(app.voteInfos) // TODO: identify if this is needed ctx = ctx.WithConsensusParams(app.GetConsensusParams(ctx)) @@ -884,7 +893,10 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res // Attempt to execute all messages and only update state if all messages pass // and we're in DeliverTx. Note, runMsgs will never return a reference to a // Result if any single message fails or does not have a registered Handler. - result, err = app.runMsgs(runMsgCtx, msgs, mode) + msgsV2, err := tx.GetMsgsV2() + if err == nil { + result, err = app.runMsgs(runMsgCtx, msgs, msgsV2, mode) + } if err == nil { // Run optional postHandlers. // @@ -924,7 +936,7 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res // and DeliverTx. An error is returned if any single message fails or if a // Handler does not exist for a given message route. Otherwise, a reference to a // Result is returned. The caller must not commit state if an error is returned. -func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode execMode) (*sdk.Result, error) { +func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, msgsV2 []protov2.Message, mode execMode) (*sdk.Result, error) { events := sdk.EmptyEvents() var msgResponses []*codectypes.Any @@ -946,7 +958,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode execMode) (*sd } // create message events - msgEvents := createEvents(msgResult.GetEvents(), msg) + msgEvents := createEvents(app.cdc, msgResult.GetEvents(), msg, msgsV2[i]) // append message events and data // @@ -991,13 +1003,21 @@ func makeABCIData(msgResponses []*codectypes.Any) ([]byte, error) { return proto.Marshal(&sdk.TxMsgData{MsgResponses: msgResponses}) } -func createEvents(events sdk.Events, msg sdk.Msg) sdk.Events { +func createEvents(cdc codec.Codec, events sdk.Events, msg sdk.Msg, msgV2 protov2.Message) sdk.Events { eventMsgName := sdk.MsgTypeURL(msg) msgEvent := sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, eventMsgName)) // we set the signer attribute as the sender - if len(msg.GetSigners()) > 0 && !msg.GetSigners()[0].Empty() { - msgEvent = msgEvent.AppendAttributes(sdk.NewAttribute(sdk.AttributeKeySender, msg.GetSigners()[0].String())) + signers, err := cdc.GetMsgV2Signers(msgV2) + if err != nil { + panic(err) + } + if len(signers) > 0 && signers[0] != nil { + addrStr, err := cdc.InterfaceRegistry().SigningContext().AddressCodec().BytesToString(signers[0]) + if err != nil { + panic(err) + } + msgEvent = msgEvent.AppendAttributes(sdk.NewAttribute(sdk.AttributeKeySender, addrStr)) } // verify that events have no module attribute set diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index afc192fa964a..e6061b4eb744 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -9,23 +9,25 @@ import ( errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" + abci "github.com/cometbft/cometbft/abci/types" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/stretchr/testify/require" + "cosmossdk.io/store/metrics" pruningtypes "cosmossdk.io/store/pruning/types" "cosmossdk.io/store/rootmulti" "cosmossdk.io/store/snapshots" snapshottypes "cosmossdk.io/store/snapshots/types" storetypes "cosmossdk.io/store/types" - abci "github.com/cometbft/cometbft/abci/types" - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - dbm "github.com/cosmos/cosmos-db" - "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/baseapp" baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" + codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" ) @@ -56,7 +58,7 @@ type ( ) func NewBaseAppSuite(t *testing.T, opts ...func(*baseapp.BaseApp)) *BaseAppSuite { - cdc := codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + cdc := codectestutil.CodecOptions{}.NewCodec() baseapptestutil.RegisterInterfaces(cdc.InterfaceRegistry()) txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes) @@ -107,6 +109,7 @@ func NewBaseAppSuiteWithSnapshots(t *testing.T, cfg SnapshotsConfig, opts ...fun for height := int64(1); height <= int64(cfg.blocks); height++ { + _, _, addr := testdata.KeyTestPubAddr() txs := [][]byte{} for txNum := 0; txNum < cfg.blockTxs; txNum++ { msgs := []sdk.Msg{} @@ -117,7 +120,7 @@ func NewBaseAppSuiteWithSnapshots(t *testing.T, cfg SnapshotsConfig, opts ...fun _, err := r.Read(value) require.NoError(t, err) - msgs = append(msgs, &baseapptestutil.MsgKeyValue{Key: key, Value: value}) + msgs = append(msgs, &baseapptestutil.MsgKeyValue{Key: key, Value: value, Signer: addr.String()}) keyCounter++ } diff --git a/baseapp/msg_service_router_test.go b/baseapp/msg_service_router_test.go index eeee401a7d82..23acbe99409b 100644 --- a/baseapp/msg_service_router_test.go +++ b/baseapp/msg_service_router_test.go @@ -115,9 +115,14 @@ func TestMsgService(t *testing.T) { app.MsgServiceRouter(), testdata.MsgServerImpl{}, ) - app.FinalizeBlock(&abci.RequestFinalizeBlock{Height: 1}) + _, err = app.FinalizeBlock(&abci.RequestFinalizeBlock{Height: 1}) + require.NoError(t, err) - msg := testdata.MsgCreateDog{Dog: &testdata.Dog{Name: "Spot"}} + _, _, addr := testdata.KeyTestPubAddr() + msg := testdata.MsgCreateDog{ + Dog: &testdata.Dog{Name: "Spot"}, + Owner: addr.String(), + } txBuilder := txConfig.NewTxBuilder() txBuilder.SetFeeAmount(testdata.NewTestFeeAmount()) diff --git a/baseapp/options.go b/baseapp/options.go index 794df1306ee5..6e1eee268636 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -11,6 +11,7 @@ import ( storetypes "cosmossdk.io/store/types" dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/mempool" @@ -256,6 +257,7 @@ func (app *BaseApp) SetInterfaceRegistry(registry types.InterfaceRegistry) { app.interfaceRegistry = registry app.grpcQueryRouter.SetInterfaceRegistry(registry) app.msgServiceRouter.SetInterfaceRegistry(registry) + app.cdc = codec.NewProtoCodec(registry) } // SetTxDecoder sets the TxDecoder if it wasn't provided in the BaseApp constructor. diff --git a/baseapp/testutil/messages.pb.go b/baseapp/testutil/messages.pb.go index 533a75289217..2884ff0f649a 100644 --- a/baseapp/testutil/messages.pb.go +++ b/baseapp/testutil/messages.pb.go @@ -31,8 +31,9 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type MsgCounter struct { - Counter int64 `protobuf:"varint,1,opt,name=counter,proto3" json:"counter,omitempty"` - FailOnHandler bool `protobuf:"varint,2,opt,name=fail_on_handler,json=failOnHandler,proto3" json:"fail_on_handler,omitempty"` + Counter int64 `protobuf:"varint,1,opt,name=counter,proto3" json:"counter,omitempty"` + FailOnHandler bool `protobuf:"varint,2,opt,name=fail_on_handler,json=failOnHandler,proto3" json:"fail_on_handler,omitempty"` + Signer string `protobuf:"bytes,3,opt,name=signer,proto3" json:"signer,omitempty"` } func (m *MsgCounter) Reset() { *m = MsgCounter{} } @@ -82,9 +83,17 @@ func (m *MsgCounter) GetFailOnHandler() bool { return false } +func (m *MsgCounter) GetSigner() string { + if m != nil { + return m.Signer + } + return "" +} + type MsgCounter2 struct { - Counter int64 `protobuf:"varint,1,opt,name=counter,proto3" json:"counter,omitempty"` - FailOnHandler bool `protobuf:"varint,2,opt,name=fail_on_handler,json=failOnHandler,proto3" json:"fail_on_handler,omitempty"` + Counter int64 `protobuf:"varint,1,opt,name=counter,proto3" json:"counter,omitempty"` + FailOnHandler bool `protobuf:"varint,2,opt,name=fail_on_handler,json=failOnHandler,proto3" json:"fail_on_handler,omitempty"` + Signer string `protobuf:"bytes,3,opt,name=signer,proto3" json:"signer,omitempty"` } func (m *MsgCounter2) Reset() { *m = MsgCounter2{} } @@ -134,6 +143,13 @@ func (m *MsgCounter2) GetFailOnHandler() bool { return false } +func (m *MsgCounter2) GetSigner() string { + if m != nil { + return m.Signer + } + return "" +} + type MsgCreateCounterResponse struct { } @@ -277,32 +293,32 @@ func init() { func init() { proto.RegisterFile("messages.proto", fileDescriptor_4dc296cbfe5ffcd5) } var fileDescriptor_4dc296cbfe5ffcd5 = []byte{ - // 387 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x92, 0xcf, 0xca, 0xd3, 0x40, - 0x14, 0xc5, 0x1b, 0x83, 0xdf, 0x57, 0x6f, 0xab, 0x96, 0x50, 0x34, 0x8d, 0x10, 0x4a, 0x16, 0x52, - 0x84, 0x66, 0x30, 0xee, 0xda, 0x9d, 0x22, 0x55, 0x44, 0x0b, 0x11, 0x5c, 0x74, 0x53, 0x26, 0xe9, - 0xed, 0x34, 0x34, 0x99, 0x09, 0x99, 0x49, 0xa1, 0x5b, 0x9f, 0xc0, 0x47, 0xf1, 0x31, 0x5c, 0x76, - 0xe9, 0x52, 0xda, 0x85, 0xaf, 0x21, 0xf9, 0xd7, 0xba, 0xb0, 0xae, 0xbe, 0xd5, 0xdc, 0x73, 0x2e, - 0xf9, 0x9d, 0xcc, 0x61, 0xe0, 0x51, 0x82, 0x52, 0x52, 0x86, 0xd2, 0x4d, 0x33, 0xa1, 0x84, 0xf5, - 0x34, 0x14, 0x32, 0x11, 0x92, 0x24, 0x92, 0x91, 0xdd, 0xcb, 0xe2, 0xa8, 0x17, 0x7d, 0x26, 0x98, - 0x28, 0x47, 0x52, 0x4c, 0xb5, 0x3b, 0x60, 0x42, 0xb0, 0x18, 0x49, 0xa9, 0x82, 0x7c, 0x4d, 0x28, - 0xdf, 0x57, 0x2b, 0xe7, 0x13, 0xc0, 0x47, 0xc9, 0xde, 0x88, 0x9c, 0x2b, 0xcc, 0x0c, 0x13, 0x6e, - 0xc3, 0x6a, 0x34, 0xb5, 0xa1, 0x36, 0xd2, 0xfd, 0x46, 0x1a, 0xcf, 0xe1, 0xf1, 0x9a, 0x46, 0xf1, - 0x52, 0xf0, 0xe5, 0x86, 0xf2, 0x55, 0x8c, 0x99, 0x79, 0x6f, 0xa8, 0x8d, 0xda, 0xfe, 0xc3, 0xc2, - 0x9e, 0xf3, 0x77, 0x95, 0xe9, 0xcc, 0xa1, 0x73, 0xe1, 0x79, 0x77, 0x00, 0xb4, 0xc0, 0x2c, 0x80, - 0x19, 0x52, 0x85, 0x35, 0xd6, 0x47, 0x99, 0x0a, 0x2e, 0xd1, 0x59, 0x94, 0x61, 0x1f, 0x70, 0xff, - 0x85, 0xc6, 0x39, 0x1a, 0x3d, 0xd0, 0xb7, 0xb8, 0x2f, 0x83, 0xba, 0x7e, 0x31, 0x1a, 0x7d, 0xb8, - 0xbf, 0x2b, 0x56, 0x25, 0xba, 0xeb, 0x57, 0xc2, 0x78, 0x02, 0x37, 0x32, 0x62, 0x1c, 0x33, 0x53, - 0x1f, 0x6a, 0xa3, 0x07, 0x7e, 0xad, 0x26, 0x9d, 0xaf, 0xbf, 0xbf, 0xbf, 0xa8, 0x85, 0xf3, 0x0c, - 0x06, 0xe7, 0xdc, 0x26, 0xa1, 0x09, 0xf6, 0xde, 0xc2, 0x6d, 0x53, 0xd9, 0x04, 0x7a, 0xef, 0x79, - 0x98, 0x61, 0x82, 0x5c, 0x35, 0x5e, 0xc7, 0xbd, 0x74, 0x60, 0x0d, 0xdc, 0x6b, 0xff, 0xef, 0xcd, - 0xa0, 0x7d, 0x6e, 0x6a, 0xfa, 0x0f, 0x4e, 0xf7, 0x2f, 0x8e, 0xf7, 0x3f, 0xd0, 0x14, 0xda, 0xe7, - 0x16, 0x08, 0xe8, 0x9f, 0x51, 0x55, 0xdf, 0x36, 0xa6, 0x65, 0xb9, 0x57, 0x2f, 0xf3, 0x7a, 0xf6, - 0xe3, 0x68, 0x6b, 0x87, 0xa3, 0xad, 0xfd, 0x3a, 0xda, 0xda, 0xb7, 0x93, 0xdd, 0x3a, 0x9c, 0xec, - 0xd6, 0xcf, 0x93, 0xdd, 0x5a, 0x8c, 0x59, 0xa4, 0x36, 0x79, 0xe0, 0x86, 0x22, 0x21, 0xf5, 0x8b, - 0xab, 0x8e, 0xb1, 0x5c, 0x6d, 0x49, 0x40, 0x25, 0xd2, 0x34, 0x25, 0x0a, 0xa5, 0xca, 0x55, 0x14, - 0x07, 0x37, 0xe5, 0x93, 0x7a, 0xf5, 0x27, 0x00, 0x00, 0xff, 0xff, 0xea, 0x9d, 0x1c, 0xeb, 0xae, - 0x02, 0x00, 0x00, + // 390 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x92, 0xcf, 0xaa, 0xd3, 0x40, + 0x14, 0xc6, 0x1b, 0x83, 0x6d, 0x3d, 0xad, 0x5a, 0x42, 0xd1, 0x34, 0x42, 0x28, 0x5d, 0x48, 0x11, + 0x9a, 0xc1, 0xb8, 0x6b, 0x77, 0x8a, 0x54, 0x11, 0x11, 0x22, 0xb8, 0xe8, 0xa6, 0x4c, 0xd2, 0xd3, + 0x69, 0x68, 0x32, 0x13, 0x32, 0x93, 0x42, 0xb7, 0x3e, 0x81, 0x8f, 0xe2, 0x63, 0xb8, 0xec, 0xd2, + 0xa5, 0xb4, 0x0b, 0x5f, 0x43, 0xf2, 0xaf, 0x75, 0x71, 0x7b, 0xb9, 0xab, 0xbb, 0x9a, 0xf3, 0x7d, + 0x87, 0x9c, 0xdf, 0xc9, 0xc7, 0x81, 0x27, 0x31, 0x4a, 0x49, 0x19, 0x4a, 0x27, 0x49, 0x85, 0x12, + 0x56, 0x9f, 0x09, 0x26, 0x8a, 0x92, 0xe4, 0x55, 0xe5, 0x0e, 0x98, 0x10, 0x2c, 0x42, 0x52, 0x28, + 0x3f, 0x5b, 0x13, 0xca, 0xf7, 0x55, 0xeb, 0x79, 0x20, 0x64, 0x2c, 0x24, 0x89, 0x25, 0x23, 0xbb, + 0xd7, 0xf9, 0x53, 0x36, 0x46, 0x12, 0xe0, 0xb3, 0x64, 0xef, 0x44, 0xc6, 0x15, 0xa6, 0x86, 0x09, + 0xad, 0xa0, 0x2c, 0x4d, 0x6d, 0xa8, 0x8d, 0x75, 0xaf, 0x96, 0xc6, 0x4b, 0x78, 0xba, 0xa6, 0x61, + 0xb4, 0x14, 0x7c, 0xb9, 0xa1, 0x7c, 0x15, 0x61, 0x6a, 0x3e, 0x18, 0x6a, 0xe3, 0xb6, 0xf7, 0x38, + 0xb7, 0xbf, 0xf0, 0x0f, 0xa5, 0x69, 0x3c, 0x83, 0xa6, 0x0c, 0x19, 0xc7, 0xd4, 0xd4, 0x87, 0xda, + 0xf8, 0x91, 0x57, 0xa9, 0x69, 0xe7, 0xfb, 0xdf, 0x9f, 0xaf, 0x2a, 0x31, 0x52, 0xd0, 0xb9, 0x40, + 0xdd, 0xfb, 0xa2, 0x5a, 0x60, 0xe6, 0xd4, 0x14, 0xa9, 0xc2, 0x8a, 0xed, 0xa1, 0x4c, 0x04, 0x97, + 0x38, 0x5a, 0x14, 0x1b, 0x7d, 0xc2, 0xfd, 0x37, 0x1a, 0x65, 0x68, 0xf4, 0x40, 0xdf, 0xe2, 0xbe, + 0xd8, 0xa6, 0xeb, 0xe5, 0xa5, 0xd1, 0x87, 0x87, 0xbb, 0xbc, 0x55, 0xf0, 0xbb, 0x5e, 0x29, 0xee, + 0xc6, 0x7d, 0x01, 0x83, 0x33, 0xb7, 0x26, 0xd4, 0x60, 0xf7, 0x3d, 0xb4, 0xea, 0xf0, 0xa7, 0xd0, + 0xfb, 0xc8, 0x83, 0x14, 0x63, 0xe4, 0xaa, 0xf6, 0x3a, 0xce, 0x25, 0x28, 0x6b, 0xe0, 0x5c, 0xdb, + 0xdf, 0x9d, 0x43, 0xfb, 0x1c, 0xe7, 0xec, 0x86, 0x39, 0xdd, 0xff, 0xe6, 0xb8, 0xb7, 0x0d, 0x9a, + 0x41, 0xfb, 0x9c, 0x02, 0x01, 0xfd, 0x2b, 0xaa, 0xf2, 0xdb, 0xda, 0xb4, 0x2c, 0xe7, 0xea, 0xcf, + 0xbc, 0x9d, 0xff, 0x3a, 0xda, 0xda, 0xe1, 0x68, 0x6b, 0x7f, 0x8e, 0xb6, 0xf6, 0xe3, 0x64, 0x37, + 0x0e, 0x27, 0xbb, 0xf1, 0xfb, 0x64, 0x37, 0x16, 0x13, 0x16, 0xaa, 0x4d, 0xe6, 0x3b, 0x81, 0x88, + 0x49, 0x75, 0x8a, 0xe5, 0x33, 0x91, 0xab, 0x2d, 0xf1, 0xa9, 0x44, 0x9a, 0x24, 0x44, 0xa1, 0x54, + 0x99, 0x0a, 0x23, 0xbf, 0x59, 0x1c, 0xe7, 0x9b, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x44, 0x91, + 0x2d, 0xb3, 0xf8, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -549,6 +565,13 @@ func (m *MsgCounter) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintMessages(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x1a + } if m.FailOnHandler { i-- if m.FailOnHandler { @@ -587,6 +610,13 @@ func (m *MsgCounter2) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintMessages(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x1a + } if m.FailOnHandler { i-- if m.FailOnHandler { @@ -718,6 +748,10 @@ func (m *MsgCounter) Size() (n int) { if m.FailOnHandler { n += 2 } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovMessages(uint64(l)) + } return n } @@ -733,6 +767,10 @@ func (m *MsgCounter2) Size() (n int) { if m.FailOnHandler { n += 2 } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovMessages(uint64(l)) + } return n } @@ -849,6 +887,38 @@ func (m *MsgCounter) Unmarshal(dAtA []byte) error { } } m.FailOnHandler = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMessages + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMessages + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipMessages(dAtA[iNdEx:]) @@ -938,6 +1008,38 @@ func (m *MsgCounter2) Unmarshal(dAtA []byte) error { } } m.FailOnHandler = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMessages + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMessages + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipMessages(dAtA[iNdEx:]) diff --git a/baseapp/testutil/messages.proto b/baseapp/testutil/messages.proto index f5e1fb4b5684..1cce9dba5ded 100644 --- a/baseapp/testutil/messages.proto +++ b/baseapp/testutil/messages.proto @@ -1,19 +1,25 @@ syntax = "proto3"; -import "cosmos/msg/v1/msg.proto"; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; +import "cosmos/msg/v1/msg.proto"; option go_package = "github.com/cosmos/cosmos-sdk/baseapp/testutil"; message MsgCounter { + option (cosmos.msg.v1.signer) = "signer"; + int64 counter = 1; bool fail_on_handler = 2; + string signer = 3; } message MsgCounter2 { + option (cosmos.msg.v1.signer) = "signer"; + int64 counter = 1; bool fail_on_handler = 2; + string signer = 3; } message MsgCreateCounterResponse {} diff --git a/baseapp/utils_test.go b/baseapp/utils_test.go index 52f1e67c49b5..e436b47ad73e 100644 --- a/baseapp/utils_test.go +++ b/baseapp/utils_test.go @@ -15,16 +15,18 @@ import ( runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" - "cosmossdk.io/core/appconfig" "cosmossdk.io/depinject" errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" - storetypes "cosmossdk.io/store/types" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" cmttypes "github.com/cometbft/cometbft/types" dbm "github.com/cosmos/cosmos-db" "github.com/stretchr/testify/require" + "cosmossdk.io/core/appconfig" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + "github.com/cosmos/cosmos-sdk/baseapp" baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil" "github.com/cosmos/cosmos-sdk/client" @@ -322,9 +324,10 @@ func parseTxMemo(t *testing.T, tx sdk.Tx) (counter int64, failOnAnte bool) { } func newTxCounter(t *testing.T, cfg client.TxConfig, counter int64, msgCounters ...int64) signing.Tx { + _, _, addr := testdata.KeyTestPubAddr() msgs := make([]sdk.Msg, 0, len(msgCounters)) for _, c := range msgCounters { - msg := &baseapptestutil.MsgCounter{Counter: c, FailOnHandler: false} + msg := &baseapptestutil.MsgCounter{Counter: c, FailOnHandler: false, Signer: addr.String()} msgs = append(msgs, msg) } diff --git a/client/tx_config.go b/client/tx_config.go index 5b74c0d175cb..655e19cbeba7 100644 --- a/client/tx_config.go +++ b/client/tx_config.go @@ -30,6 +30,7 @@ type ( NewTxBuilder() TxBuilder WrapTxBuilder(sdk.Tx) (TxBuilder, error) SignModeHandler() *txsigning.HandlerMap + SigningContext() *txsigning.Context } // TxBuilder defines an interface which an application-defined concrete transaction diff --git a/codec/bench_test.go b/codec/bench_test.go new file mode 100644 index 000000000000..cb3c821213e1 --- /dev/null +++ b/codec/bench_test.go @@ -0,0 +1,96 @@ +package codec_test + +import ( + "testing" + + bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" + "github.com/stretchr/testify/require" + protov2 "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/dynamicpb" + + codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func BenchmarkLegacyGetSigners(b *testing.B) { + _, _, addr := testdata.KeyTestPubAddr() + msg := &banktypes.MsgSend{ + FromAddress: addr.String(), + ToAddress: "", + Amount: nil, + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = msg.GetSigners() + } +} + +func BenchmarkProtoreflectGetSigners(b *testing.B) { + cdc := codectestutil.CodecOptions{}.NewCodec() + signingCtx := cdc.InterfaceRegistry().SigningContext() + _, _, addr := testdata.KeyTestPubAddr() + // use a pulsar message + msg := &bankv1beta1.MsgSend{ + FromAddress: addr.String(), + ToAddress: "", + Amount: nil, + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := signingCtx.GetSigners(msg) + if err != nil { + panic(err) + } + } +} + +func BenchmarkProtoreflectGetSignersWithUnmarshal(b *testing.B) { + cdc := codectestutil.CodecOptions{}.NewCodec() + _, _, addr := testdata.KeyTestPubAddr() + // start with a protoreflect message + msg := &banktypes.MsgSend{ + FromAddress: addr.String(), + ToAddress: "", + Amount: nil, + } + // marshal to an any first because this is what we get from the wire + a, err := codectypes.NewAnyWithValue(msg) + require.NoError(b, err) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _, err := cdc.GetMsgAnySigners(a) + if err != nil { + panic(err) + } + } +} + +func BenchmarkProtoreflectGetSignersDynamicpb(b *testing.B) { + cdc := codectestutil.CodecOptions{}.NewCodec() + signingCtx := cdc.InterfaceRegistry().SigningContext() + _, _, addr := testdata.KeyTestPubAddr() + msg := &bankv1beta1.MsgSend{ + FromAddress: addr.String(), + ToAddress: "", + Amount: nil, + } + bz, err := protov2.Marshal(msg) + require.NoError(b, err) + + dynamicmsg := dynamicpb.NewMessage(msg.ProtoReflect().Descriptor()) + err = protov2.Unmarshal(bz, dynamicmsg) + require.NoError(b, err) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := signingCtx.GetSigners(dynamicmsg) + if err != nil { + panic(err) + } + } +} diff --git a/codec/testutil/codec.go b/codec/testutil/codec.go new file mode 100644 index 000000000000..2f08a4ad3b4c --- /dev/null +++ b/codec/testutil/codec.go @@ -0,0 +1,43 @@ +package testutil + +import ( + "github.com/cosmos/gogoproto/proto" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/address" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" +) + +// CodecOptions are options for creating a test codec. +type CodecOptions struct { + AccAddressPrefix string + ValAddressPrefix string +} + +// NewInterfaceRegistry returns a new InterfaceRegistry with the given options. +func (o CodecOptions) NewInterfaceRegistry() codectypes.InterfaceRegistry { + accAddressPrefix := o.AccAddressPrefix + if accAddressPrefix == "" { + accAddressPrefix = "cosmos" + } + + valAddressPrefix := o.ValAddressPrefix + if valAddressPrefix == "" { + valAddressPrefix = "cosmosvaloper" + } + + ir, err := codectypes.NewInterfaceRegistryWithOptions(codectypes.InterfaceRegistryOptions{ + ProtoFiles: proto.HybridResolver, + AddressCodec: address.NewBech32Codec(accAddressPrefix), + ValidatorAddressCodec: address.NewBech32Codec(valAddressPrefix), + }) + if err != nil { + panic(err) + } + return ir +} + +// NewCodec returns a new codec with the given options. +func (o CodecOptions) NewCodec() *codec.ProtoCodec { + return codec.NewProtoCodec(o.NewInterfaceRegistry()) +} diff --git a/runtime/module.go b/runtime/module.go index d9107a3ff709..a84019036f1a 100644 --- a/runtime/module.go +++ b/runtime/module.go @@ -19,6 +19,7 @@ import ( "cosmossdk.io/core/header" "cosmossdk.io/core/store" storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec/address" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" @@ -98,9 +99,15 @@ func ProvideApp() ( } interfaceRegistry, err := codectypes.NewInterfaceRegistryWithOptions(codectypes.InterfaceRegistryOptions{ - ProtoFiles: protoFiles, - AddressCodec: globalAccAddressCodec{}, - ValidatorAddressCodec: globalValAddressCodec{}, + ProtoFiles: proto.HybridResolver, + // using the global prefixes is a temporary solution until we refactor this + // to get the address.Codec's from the container + AddressCodec: address.Bech32Codec{ + Bech32Prefix: sdk.GetConfig().GetBech32AccountAddrPrefix(), + }, + ValidatorAddressCodec: address.Bech32Codec{ + Bech32Prefix: sdk.GetConfig().GetBech32ValidatorAddrPrefix(), + }, }) if err != nil { return nil, nil, nil, nil, nil, nil, nil, nil, nil, err @@ -243,33 +250,3 @@ func ProvideHeaderInfoService(app *AppBuilder) header.Service { func ProvideBasicManager(app *AppBuilder) module.BasicManager { return app.app.basicManager } - -// globalAccAddressCodec is a temporary address codec that we will use until we -// can populate it with the correct bech32 prefixes without depending on the global. -type globalAccAddressCodec struct{} - -func (g globalAccAddressCodec) StringToBytes(text string) ([]byte, error) { - if text == "" { - return nil, nil - } - return sdk.AccAddressFromBech32(text) -} - -func (g globalAccAddressCodec) BytesToString(bz []byte) (string, error) { - if bz == nil { - return "", nil - } - return sdk.AccAddress(bz).String(), nil -} - -// globalValAddressCodec is a temporary address codec that we will use until we -// can populate it with the correct bech32 prefixes without depending on the global. -type globalValAddressCodec struct{} - -func (g globalValAddressCodec) StringToBytes(text string) ([]byte, error) { - return sdk.ValAddressFromBech32(text) -} - -func (g globalValAddressCodec) BytesToString(bz []byte) (string, error) { - return sdk.ValAddress(bz).String(), nil -} diff --git a/server/mock/app.go b/server/mock/app.go index bc5af766258d..d5ebd12f0cf1 100644 --- a/server/mock/app.go +++ b/server/mock/app.go @@ -12,11 +12,11 @@ import ( "google.golang.org/grpc" "cosmossdk.io/log" - storetypes "cosmossdk.io/store/types" + storetypes "cosmossdk.io/store/types" bam "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/codec/testutil" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" @@ -37,8 +37,9 @@ func NewApp(rootDir string, logger log.Logger) (servertypes.ABCI, error) { baseApp.MountStores(capKeyMainStore) baseApp.SetInitChainer(InitChainer(capKeyMainStore)) - interfaceRegistry := codectypes.NewInterfaceRegistry() + interfaceRegistry := testutil.CodecOptions{}.NewInterfaceRegistry() interfaceRegistry.RegisterImplementations((*sdk.Msg)(nil), &KVStoreTx{}) + baseApp.SetInterfaceRegistry(interfaceRegistry) router := bam.NewMsgServiceRouter() router.SetInterfaceRegistry(interfaceRegistry) diff --git a/server/mock/tx.go b/server/mock/tx.go index e494fc470c3f..941c002e0036 100644 --- a/server/mock/tx.go +++ b/server/mock/tx.go @@ -4,6 +4,9 @@ import ( "bytes" "fmt" + bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" + protov2 "google.golang.org/protobuf/proto" + "github.com/cosmos/cosmos-sdk/x/auth/signing" errorsmod "cosmossdk.io/errors" @@ -83,7 +86,7 @@ var ( ) func NewTx(key, value string, accAddress sdk.AccAddress) *KVStoreTx { - bytes := fmt.Sprintf("%s=%s", key, value) + bytes := fmt.Sprintf("%s=%s=%s", key, value, accAddress) return &KVStoreTx{ key: []byte(key), value: []byte(value), @@ -100,6 +103,10 @@ func (msg *KVStoreTx) GetMsgs() []sdk.Msg { return []sdk.Msg{msg} } +func (msg *KVStoreTx) GetMsgsV2() ([]protov2.Message, error) { + return []protov2.Message{&bankv1beta1.MsgSend{FromAddress: msg.address.String()}}, nil // this is a hack for tests +} + func (msg *KVStoreTx) GetSignBytes() []byte { return msg.bytes } @@ -109,8 +116,8 @@ func (msg *KVStoreTx) ValidateBasic() error { return nil } -func (msg *KVStoreTx) GetSigners() []sdk.AccAddress { - return nil +func (msg *KVStoreTx) GetSigners() ([][]byte, error) { + return nil, nil } func (msg *KVStoreTx) GetPubKeys() ([]cryptotypes.PubKey, error) { panic("GetPubKeys not implemented") } @@ -128,6 +135,9 @@ func decodeTx(txBytes []byte) (sdk.Tx, error) { case 2: k, v := split[0], split[1] tx = &KVStoreTx{k, v, txBytes, nil} + case 3: + k, v, addr := split[0], split[1], split[2] + tx = &KVStoreTx{k, v, txBytes, addr} default: return nil, errorsmod.Wrap(sdkerrors.ErrTxDecode, "too many '='") } diff --git a/simapp/app.go b/simapp/app.go index 25e122a8c8c1..904a0e0818bd 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -9,20 +9,22 @@ import ( "os" "path/filepath" + "cosmossdk.io/log" + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" "cosmossdk.io/client/v2/autocli" "cosmossdk.io/core/appmodule" - "cosmossdk.io/log" + "github.com/cosmos/cosmos-sdk/codec/address" authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec" + "github.com/cosmos/cosmos-sdk/x/auth/tx" abci "github.com/cometbft/cometbft/abci/types" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/proto" "github.com/spf13/cast" - simappparams "cosmossdk.io/simapp/params" storetypes "cosmossdk.io/store/types" "cosmossdk.io/x/evidence" evidencekeeper "cosmossdk.io/x/evidence/keeper" @@ -133,6 +135,36 @@ var ( _ servertypes.Application = (*SimApp)(nil) ) +// stdAccAddressCodec is a temporary address codec that we will use until we +// can populate it with the correct bech32 prefixes without depending on the global. +type stdAccAddressCodec struct{} + +func (g stdAccAddressCodec) StringToBytes(text string) ([]byte, error) { + if text == "" { + return nil, nil + } + return sdk.AccAddressFromBech32(text) +} + +func (g stdAccAddressCodec) BytesToString(bz []byte) (string, error) { + if bz == nil { + return "", nil + } + return sdk.AccAddress(bz).String(), nil +} + +// stdValAddressCodec is a temporary address codec that we will use until we +// can populate it with the correct bech32 prefixes without depending on the global. +type stdValAddressCodec struct{} + +func (g stdValAddressCodec) StringToBytes(text string) ([]byte, error) { + return sdk.ValAddressFromBech32(text) +} + +func (g stdValAddressCodec) BytesToString(bz []byte) (string, error) { + return sdk.ValAddress(bz).String(), nil +} + // SimApp extends an ABCI application, but with most of its parameters exported. // They are exported for convenience in creating helper functions, as object // capabilities aren't needed for testing. @@ -195,12 +227,18 @@ func NewSimApp( appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *SimApp { - encodingConfig := simappparams.MakeTestEncodingConfig() - - appCodec := encodingConfig.Codec - legacyAmino := encodingConfig.Amino - interfaceRegistry := encodingConfig.InterfaceRegistry - txConfig := encodingConfig.TxConfig + interfaceRegistry, _ := types.NewInterfaceRegistryWithOptions(types.InterfaceRegistryOptions{ + ProtoFiles: proto.HybridResolver, + AddressCodec: address.Bech32Codec{ + Bech32Prefix: sdk.GetConfig().GetBech32AccountAddrPrefix(), + }, + ValidatorAddressCodec: address.Bech32Codec{ + Bech32Prefix: sdk.GetConfig().GetBech32ValidatorAddrPrefix(), + }, + }) + appCodec := codec.NewProtoCodec(interfaceRegistry) + legacyAmino := codec.NewLegacyAmino() + txConfig := tx.NewTxConfig(appCodec, tx.DefaultSignModes) std.RegisterLegacyAminoCodec(legacyAmino) std.RegisterInterfaces(interfaceRegistry) @@ -369,7 +407,7 @@ func NewSimApp( app.ModuleManager = module.NewManager( genutil.NewAppModule( app.AccountKeeper, app.StakingKeeper, app, - encodingConfig.TxConfig, + txConfig, ), auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), vesting.NewAppModule(app.AccountKeeper, app.BankKeeper), @@ -405,8 +443,8 @@ func NewSimApp( }, ), }) - app.BasicModuleManager.RegisterLegacyAminoCodec(encodingConfig.Amino) - app.BasicModuleManager.RegisterInterfaces(encodingConfig.InterfaceRegistry) + app.BasicModuleManager.RegisterLegacyAminoCodec(legacyAmino) + app.BasicModuleManager.RegisterInterfaces(interfaceRegistry) // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the @@ -488,7 +526,7 @@ func NewSimApp( app.SetInitChainer(app.InitChainer) app.SetBeginBlocker(app.BeginBlocker) app.SetEndBlocker(app.EndBlocker) - app.setAnteHandler(encodingConfig.TxConfig) + app.setAnteHandler(txConfig) // In v0.46, the SDK introduces _postHandlers_. PostHandlers are like // antehandlers, but are run _after_ the `runMsgs` execution. They are also diff --git a/tests/e2e/auth/suite.go b/tests/e2e/auth/suite.go index bc77fe91805e..7b81085ba106 100644 --- a/tests/e2e/auth/suite.go +++ b/tests/e2e/auth/suite.go @@ -561,6 +561,7 @@ func (s *E2ETestSuite) TestCLIQueryTxCmdByEvents() { s.Require().Contains(err.Error(), tc.expectErrStr) } else { var result sdk.TxResponse + s.Require().NoError(err) s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &result)) s.Require().NotNil(result.Height) } @@ -743,7 +744,9 @@ func (s *E2ETestSuite) TestCLISendGenerateSignAndBroadcast() { sigs, err = txBuilder.GetTx().GetSignaturesV2() s.Require().NoError(err) s.Require().Equal(1, len(sigs)) - s.Require().Equal(val1.Address.String(), txBuilder.GetTx().GetSigners()[0].String()) + signers, err := txBuilder.GetTx().GetSigners() + s.Require().NoError(err) + s.Require().Equal([]byte(val1.Address), signers[0]) // Write the output to disk signedTxFile := testutil.WriteToNewTempFile(s.T(), signedTx.String()) @@ -1580,7 +1583,9 @@ func (s *E2ETestSuite) TestSignWithMultiSignersAminoJSON() { ) txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)))) txBuilder.SetGasLimit(testdata.NewTestGasLimit() * 2) - require.Equal([]sdk.AccAddress{val0.Address, val1.Address}, txBuilder.GetTx().GetSigners()) + signers, err := txBuilder.GetTx().GetSigners() + require.NoError(err) + require.Equal([][]byte{val0.Address, val1.Address}, signers) // Write the unsigned tx into a file. txJSON, err := val0.ClientCtx.TxConfig.TxJSONEncoder()(txBuilder.GetTx()) diff --git a/tests/e2e/tx/service_test.go b/tests/e2e/tx/service_test.go index 86761d180693..24e407969c2f 100644 --- a/tests/e2e/tx/service_test.go +++ b/tests/e2e/tx/service_test.go @@ -1102,7 +1102,9 @@ func (s *E2ETestSuite) mkTxBuilder() client.TxBuilder { txBuilder.SetFeeAmount(feeAmount) txBuilder.SetGasLimit(gasLimit) txBuilder.SetMemo("foobar") - s.Require().Equal([]sdk.AccAddress{val.Address}, txBuilder.GetTx().GetSigners()) + signers, err := txBuilder.GetTx().GetSigners() + s.Require().NoError(err) + s.Require().Equal([][]byte{val.Address}, signers) // setup txFactory txFactory := clienttx.Factory{}. @@ -1112,7 +1114,7 @@ func (s *E2ETestSuite) mkTxBuilder() client.TxBuilder { WithSignMode(signing.SignMode_SIGN_MODE_DIRECT) // Sign Tx. - err := authclient.SignTx(txFactory, val.ClientCtx, val.Moniker, txBuilder, false, true) + err = authclient.SignTx(txFactory, val.ClientCtx, val.Moniker, txBuilder, false, true) s.Require().NoError(err) return txBuilder diff --git a/tests/integration/aminojson/aminojson_test.go b/tests/integration/aminojson/aminojson_test.go index 238ea5180509..1339c60194e2 100644 --- a/tests/integration/aminojson/aminojson_test.go +++ b/tests/integration/aminojson/aminojson_test.go @@ -50,6 +50,7 @@ import ( txtypes "github.com/cosmos/cosmos-sdk/types/tx" signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" "github.com/cosmos/cosmos-sdk/x/auth/signing" "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -131,7 +132,7 @@ func TestAminoJSON_Equivalence(t *testing.T) { require.Equal(t, string(legacyAminoJSON), string(aminoJSON)) // test amino json signer handler equivalence - gogoMsg, ok := gogo.(types.Msg) + gogoMsg, ok := gogo.(legacytx.LegacyMsg) if !ok { // not signable return @@ -440,7 +441,7 @@ func TestAminoJSON_LegacyParity(t *testing.T) { require.Equal(t, string(gogoBytes), string(newGogoBytes)) // test amino json signer handler equivalence - msg, ok := tc.gogo.(types.Msg) + msg, ok := tc.gogo.(legacytx.LegacyMsg) if !ok { // not signable return diff --git a/tests/integration/tx/decode_test.go b/tests/integration/tx/decode_test.go index 43094b017085..9efc85c64745 100644 --- a/tests/integration/tx/decode_test.go +++ b/tests/integration/tx/decode_test.go @@ -23,6 +23,7 @@ import ( txtypes "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" "github.com/cosmos/cosmos-sdk/x/auth/vesting" authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" "github.com/cosmos/cosmos-sdk/x/bank" @@ -101,7 +102,7 @@ func TestDecode(t *testing.T) { Sequence: accSeq, } - gogoMsg, ok := gogo.(sdk.Msg) + gogoMsg, ok := gogo.(legacytx.LegacyMsg) require.True(t, ok) err = txBuilder.SetMsgs(gogoMsg) diff --git a/testutil/testdata/testpb/tx.proto b/testutil/testdata/testpb/tx.proto index 72df915b1363..13e48c7702a7 100644 --- a/testutil/testdata/testpb/tx.proto +++ b/testutil/testdata/testpb/tx.proto @@ -30,8 +30,9 @@ message MsgCreateDogResponse { // TestMsg is msg type for testing protobuf message using any, as defined in // https://github.com/cosmos/cosmos-sdk/issues/6213. message TestMsg { - option (gogoproto.goproto_getters) = false; option (cosmos.msg.v1.signer) = "signers"; + option (gogoproto.goproto_getters) = false; option (amino.name) = "testpb/TestMsg"; + repeated string signers = 1; } diff --git a/tools/rosetta/client_offline.go b/tools/rosetta/client_offline.go index adbf734ab538..ef01d69a113f 100644 --- a/tools/rosetta/client_offline.go +++ b/tools/rosetta/client_offline.go @@ -79,12 +79,20 @@ func (c *Client) PreprocessOperationsToOptions(_ context.Context, req *types.Con } // get the signers - signers := tx.GetSigners() + signers, err := tx.GetSigners() + if err != nil { + return nil, err + } + signersStr := make([]string, len(signers)) accountIdentifiers := make([]*types.AccountIdentifier, len(signers)) for i, sig := range signers { - addr := sig.String() + addr, err := c.config.InterfaceRegistry.SigningContext().AddressCodec().BytesToString(sig) + if err != nil { + return nil, err + } + signersStr[i] = addr accountIdentifiers[i] = &types.AccountIdentifier{ Address: addr, diff --git a/tools/rosetta/client_online.go b/tools/rosetta/client_online.go index 71fff9669690..73b52af3e6f0 100644 --- a/tools/rosetta/client_online.go +++ b/tools/rosetta/client_online.go @@ -32,6 +32,7 @@ import ( bank "github.com/cosmos/cosmos-sdk/x/bank/types" tmrpc "github.com/cometbft/cometbft/rpc/client" + "github.com/cosmos/cosmos-sdk/types/query" ) @@ -71,14 +72,12 @@ func NewClient(cfg *Config) (*Client, error) { var supportedOperations []string for _, ii := range cfg.InterfaceRegistry.ListImplementations(sdk.MsgInterfaceProtoName) { - resolvedMsg, err := cfg.InterfaceRegistry.Resolve(ii) + _, err := cfg.InterfaceRegistry.Resolve(ii) if err != nil { continue } - if _, ok := resolvedMsg.(sdk.Msg); ok { - supportedOperations = append(supportedOperations, ii) - } + supportedOperations = append(supportedOperations, ii) } supportedOperations = append( diff --git a/tools/rosetta/codec.go b/tools/rosetta/codec.go index 96242a9e044a..ff0668378890 100644 --- a/tools/rosetta/codec.go +++ b/tools/rosetta/codec.go @@ -1,9 +1,13 @@ package rosetta import ( + "github.com/cosmos/gogoproto/proto" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/address" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" authcodec "github.com/cosmos/cosmos-sdk/x/auth/types" bankcodec "github.com/cosmos/cosmos-sdk/x/bank/types" ) @@ -11,7 +15,20 @@ import ( // MakeCodec generates the codec required to interact // with the cosmos APIs used by the rosetta gateway func MakeCodec() (*codec.ProtoCodec, codectypes.InterfaceRegistry) { - ir := codectypes.NewInterfaceRegistry() + ir, err := codectypes.NewInterfaceRegistryWithOptions( + codectypes.InterfaceRegistryOptions{ + ProtoFiles: proto.HybridResolver, + AddressCodec: address.Bech32Codec{ + Bech32Prefix: sdk.GetConfig().GetBech32AccountAddrPrefix(), + }, + ValidatorAddressCodec: address.Bech32Codec{ + Bech32Prefix: sdk.GetConfig().GetBech32ValidatorAddrPrefix(), + }, + }, + ) + if err != nil { + panic(err) + } cdc := codec.NewProtoCodec(ir) authcodec.RegisterInterfaces(ir) diff --git a/tools/rosetta/converter.go b/tools/rosetta/converter.go index 36176bd0a4b2..317225c2c44f 100644 --- a/tools/rosetta/converter.go +++ b/tools/rosetta/converter.go @@ -15,6 +15,7 @@ import ( secp "github.com/decred/dcrd/dcrec/secp256k1/v4" sdkmath "cosmossdk.io/math" + crgerrs "cosmossdk.io/tools/rosetta/lib/errors" crgtypes "cosmossdk.io/tools/rosetta/lib/types" @@ -146,16 +147,11 @@ func (c converter) UnsignedTx(ops []*rosettatypes.Operation) (tx authsigning.Tx, for i := 0; i < len(ops); i++ { op := ops[i] - protoMessage, err := c.ir.Resolve(op.Type) + msg, err := c.ir.Resolve(op.Type) if err != nil { return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "operation not found: "+op.Type) } - msg, ok := protoMessage.(sdk.Msg) - if !ok { - return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "operation is not a valid supported sdk.Msg: "+op.Type) - } - err = c.Msg(op.Metadata, msg) if err != nil { return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) @@ -171,7 +167,11 @@ func (c converter) UnsignedTx(ops []*rosettatypes.Operation) (tx authsigning.Tx, } } - signers := msg.GetSigners() + signers, _, err := c.cdc.GetMsgV1Signers(msg) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) + } + // check if there are enough signers if len(signers) == 0 { return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, fmt.Sprintf("operation at index %d got no signers", op.OperationIdentifier.Index)) @@ -249,12 +249,22 @@ func (c converter) Ops(status string, msg sdk.Msg) ([]*rosettatypes.Operation, e return nil, err } - ops := make([]*rosettatypes.Operation, len(msg.GetSigners())) - for i, signer := range msg.GetSigners() { + signers, _, err := c.cdc.GetMsgV1Signers(msg) + if err != nil { + return nil, err + } + + ops := make([]*rosettatypes.Operation, len(signers)) + for i, signer := range signers { + signerStr, err := c.ir.SigningContext().AddressCodec().BytesToString(signer) + if err != nil { + return nil, err + } + op := &rosettatypes.Operation{ Type: opName, Status: &status, - Account: &rosettatypes.AccountIdentifier{Address: signer.String()}, + Account: &rosettatypes.AccountIdentifier{Address: signerStr}, Metadata: meta, } @@ -594,13 +604,24 @@ func (c converter) OpsAndSigners(txBytes []byte) (ops []*rosettatypes.Operation, return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) } - for _, signer := range txBuilder.GetTx().GetSigners() { + signerAddrs, err := txBuilder.GetTx().GetSigners() + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) + } + + for _, signer := range signerAddrs { + var signerStr string + signerStr, err = c.ir.SigningContext().AddressCodec().BytesToString(signer) + if err != nil { + return + } + signers = append(signers, &rosettatypes.AccountIdentifier{ - Address: signer.String(), + Address: signerStr, }) } - return + return ops, signers, nil } func (c converter) SignedTx(txBytes []byte, signatures []*rosettatypes.Signature) (signedTxBytes []byte, err error) { @@ -676,7 +697,11 @@ func (c converter) SigningComponents(tx authsigning.Tx, metadata *ConstructionMe return nil, nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) } - signers := tx.GetSigners() + signers, err := tx.GetSigners() + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) + } + // assert the signers data provided in options are the same as the expected signing accounts // and that the number of rosetta provided public keys equals the one of the signers if len(metadata.SignersData) != len(signers) || len(signers) != len(rosPubKeys) { @@ -704,16 +729,21 @@ func (c converter) SigningComponents(tx authsigning.Tx, metadata *ConstructionMe if err != nil { return nil, nil, err } - if !bytes.Equal(pubKey.Address().Bytes(), signer.Bytes()) { + if !bytes.Equal(pubKey.Address().Bytes(), signer) { return nil, nil, crgerrs.WrapError( crgerrs.ErrBadArgument, - fmt.Sprintf("public key at index %d does not match the expected transaction signer: %X <-> %X", i, rosPubKeys[i].Bytes, signer.Bytes()), + fmt.Sprintf("public key at index %d does not match the expected transaction signer: %X <-> %X", i, rosPubKeys[i].Bytes, signer), ) } + signerStr, err := c.ir.SigningContext().AddressCodec().BytesToString(signer) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) + } + // set the signer data signerData := authsigning.SignerData{ - Address: signer.String(), + Address: signerStr, ChainID: metadata.ChainID, AccountNumber: metadata.SignersData[i].AccountNumber, Sequence: metadata.SignersData[i].Sequence, @@ -728,7 +758,7 @@ func (c converter) SigningComponents(tx authsigning.Tx, metadata *ConstructionMe // set payload payloadsToSign[i] = &rosettatypes.SigningPayload{ - AccountIdentifier: &rosettatypes.AccountIdentifier{Address: signer.String()}, + AccountIdentifier: &rosettatypes.AccountIdentifier{Address: signerStr}, Bytes: signBytes, SignatureType: rosettatypes.Ecdsa, } diff --git a/tools/rosetta/converter_test.go b/tools/rosetta/converter_test.go index 4a30d9b793c4..7eba1fde67b1 100644 --- a/tools/rosetta/converter_test.go +++ b/tools/rosetta/converter_test.go @@ -172,9 +172,11 @@ func (s *ConverterTestSuite) TestOpsAndSigners() { ops, signers, err := s.c.ToRosetta().OpsAndSigners(txBytes) s.Require().NoError(err) - s.Require().Equal(len(ops), len(sdkTx.GetMsgs())*len(sdkTx.GetSigners()), "operation number mismatch") + signerAddrs, err := sdkTx.GetSigners() + s.Require().NoError(err) + s.Require().Equal(len(ops), len(sdkTx.GetMsgs())*len(signerAddrs), "operation number mismatch") - s.Require().Equal(len(signers), len(sdkTx.GetSigners()), "signers number mismatch") + s.Require().Equal(len(signers), len(signerAddrs), "signers number mismatch") }) } diff --git a/types/mempool/mempool_test.go b/types/mempool/mempool_test.go index 302b9a1e57b7..9ed3b4d596a9 100644 --- a/types/mempool/mempool_test.go +++ b/types/mempool/mempool_test.go @@ -8,8 +8,10 @@ import ( cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + protov2 "google.golang.org/protobuf/proto" "cosmossdk.io/log" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/mempool" @@ -52,7 +54,7 @@ type testTx struct { strAddress string } -func (tx testTx) GetSigners() []sdk.AccAddress { panic("not implemented") } +func (tx testTx) GetSigners() ([][]byte, error) { panic("not implemented") } func (tx testTx) GetPubKeys() ([]cryptotypes.PubKey, error) { panic("not implemented") } @@ -74,6 +76,8 @@ var ( func (tx testTx) GetMsgs() []sdk.Msg { return nil } +func (tx testTx) GetMsgsV2() ([]protov2.Message, error) { return nil, nil } + func (tx testTx) ValidateBasic() error { return nil } func (tx testTx) String() string { @@ -88,9 +92,11 @@ func (sigErrTx) Size() int64 { return 0 } func (sigErrTx) GetMsgs() []sdk.Msg { return nil } +func (sigErrTx) GetMsgsV2() ([]protov2.Message, error) { return nil, nil } + func (sigErrTx) ValidateBasic() error { return nil } -func (sigErrTx) GetSigners() []sdk.AccAddress { return nil } +func (sigErrTx) GetSigners() ([][]byte, error) { return nil, nil } func (sigErrTx) GetPubKeys() ([]cryptotypes.PubKey, error) { return nil, nil } diff --git a/types/module/testutil/codec.go b/types/module/testutil/codec.go index 2a6959f02dad..42efba87de1d 100644 --- a/types/module/testutil/codec.go +++ b/types/module/testutil/codec.go @@ -3,6 +3,7 @@ package testutil import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/testutil" "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/std" "github.com/cosmos/cosmos-sdk/types/module" @@ -22,7 +23,7 @@ type TestEncodingConfig struct { func MakeTestEncodingConfig(modules ...module.AppModuleBasic) TestEncodingConfig { aminoCodec := codec.NewLegacyAmino() - interfaceRegistry := types.NewInterfaceRegistry() + interfaceRegistry := testutil.CodecOptions{}.NewInterfaceRegistry() codec := codec.NewProtoCodec(interfaceRegistry) encCfg := TestEncodingConfig{ @@ -43,7 +44,7 @@ func MakeTestEncodingConfig(modules ...module.AppModuleBasic) TestEncodingConfig } func MakeTestTxConfig() client.TxConfig { - interfaceRegistry := types.NewInterfaceRegistry() + interfaceRegistry := testutil.CodecOptions{}.NewInterfaceRegistry() cdc := codec.NewProtoCodec(interfaceRegistry) return tx.NewTxConfig(cdc, tx.DefaultSignModes) } diff --git a/types/result.go b/types/result.go index 56e3ef7879ed..16382a422777 100644 --- a/types/result.go +++ b/types/result.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/gogoproto/proto" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" ) @@ -182,15 +183,15 @@ func (s SearchTxsResult) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces func (r TxResponse) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { if r.Tx != nil { - var tx Tx + var tx HasMsgs return unpacker.UnpackAny(r.Tx, &tx) } return nil } // GetTx unpacks the Tx from within a TxResponse and returns it -func (r TxResponse) GetTx() Tx { - if tx, ok := r.Tx.GetCachedValue().(Tx); ok { +func (r TxResponse) GetTx() HasMsgs { + if tx, ok := r.Tx.GetCachedValue().(HasMsgs); ok { return tx } return nil diff --git a/types/tx/types.go b/types/tx/types.go index 24de0e570b99..4df21dea7fc5 100644 --- a/types/tx/types.go +++ b/types/tx/types.go @@ -4,7 +4,9 @@ import ( "fmt" errorsmod "cosmossdk.io/errors" + protov2 "google.golang.org/protobuf/proto" + "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -17,7 +19,6 @@ const MaxGasWanted = uint64((1 << 63) - 1) // Interface implementation checks. var ( _, _, _, _ codectypes.UnpackInterfacesMessage = &Tx{}, &TxBody{}, &AuthInfo{}, &SignerInfo{} - _ sdk.Tx = &Tx{} ) // GetMsgs implements the GetMsgs method on sdk.Tx. @@ -89,41 +90,49 @@ func (t *Tx) ValidateBasic() error { return sdkerrors.ErrNoSignatures } - if len(sigs) != len(t.GetSigners()) { - return errorsmod.Wrapf( - sdkerrors.ErrUnauthorized, - "wrong number of signers; expected %d, got %d", len(t.GetSigners()), len(sigs), - ) - } - return nil } // GetSigners retrieves all the signers of a tx. // This includes all unique signers of the messages (in order), // as well as the FeePayer (if specified and not already included). -func (t *Tx) GetSigners() []sdk.AccAddress { - var signers []sdk.AccAddress +func (t *Tx) GetSigners(cdc codec.Codec) ([][]byte, []protov2.Message, error) { + var signers [][]byte seen := map[string]bool{} - for _, msg := range t.GetMsgs() { - for _, addr := range msg.GetSigners() { - if !seen[addr.String()] { - signers = append(signers, addr) - seen[addr.String()] = true + var msgsv2 []protov2.Message + for _, msg := range t.Body.Messages { + xs, msgv2, err := cdc.GetMsgAnySigners(msg) + if err != nil { + return nil, nil, err + } + + msgsv2 = append(msgsv2, msgv2) + + for _, signer := range xs { + if !seen[string(signer)] { + signers = append(signers, signer) + seen[string(signer)] = true } } } // ensure any specified fee payer is included in the required signers (at the end) feePayer := t.AuthInfo.Fee.Payer - if feePayer != "" && !seen[feePayer] { - payerAddr := sdk.MustAccAddressFromBech32(feePayer) - signers = append(signers, payerAddr) - seen[feePayer] = true + var feePayerAddr []byte + if feePayer != "" { + var err error + feePayerAddr, err = cdc.InterfaceRegistry().SigningContext().AddressCodec().StringToBytes(feePayer) + if err != nil { + return nil, nil, err + } + } + if feePayerAddr != nil && !seen[string(feePayerAddr)] { + signers = append(signers, feePayerAddr) + seen[string(feePayerAddr)] = true } - return signers + return signers, msgsv2, nil } func (t *Tx) GetGas() uint64 { @@ -134,13 +143,22 @@ func (t *Tx) GetFee() sdk.Coins { return t.AuthInfo.Fee.Amount } -func (t *Tx) FeePayer() sdk.AccAddress { +func (t *Tx) FeePayer(cdc codec.Codec) []byte { feePayer := t.AuthInfo.Fee.Payer if feePayer != "" { - return sdk.MustAccAddressFromBech32(feePayer) + feePayerAddr, err := cdc.InterfaceRegistry().SigningContext().AddressCodec().StringToBytes(feePayer) + if err != nil { + panic(err) + } + return feePayerAddr } // use first signer as default if no payer specified - return t.GetSigners()[0] + signers, _, err := t.GetSigners(cdc) + if err != nil { + panic(err) + } + + return signers[0] } func (t *Tx) FeeGranter() sdk.AccAddress { @@ -205,8 +223,8 @@ func (m *SignerInfo) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterInterface(msgResponseInterfaceProtoName, (*MsgResponse)(nil)) - registry.RegisterInterface("cosmos.tx.v1beta1.Tx", (*sdk.Tx)(nil)) - registry.RegisterImplementations((*sdk.Tx)(nil), &Tx{}) + registry.RegisterInterface("cosmos.tx.v1beta1.Tx", (*sdk.HasMsgs)(nil)) + registry.RegisterImplementations((*sdk.HasMsgs)(nil), &Tx{}) registry.RegisterInterface("cosmos.tx.v1beta1.TxExtensionOptionI", (*TxExtensionOptionI)(nil)) } diff --git a/types/tx_msg.go b/types/tx_msg.go index ba4e1238523b..898a8f6ea6d3 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -6,15 +6,20 @@ import ( strings "strings" "github.com/cosmos/gogoproto/proto" + protov2 "google.golang.org/protobuf/proto" "github.com/cosmos/cosmos-sdk/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) type ( - // Msg defines the interface a transaction message must fulfill. - Msg interface { - proto.Message + // Msg defines the interface a transaction message needed to fulfill. + Msg = proto.Message + + // LegacyMsg defines the interface a transaction message needed to fulfill up through + // v0.47. + LegacyMsg interface { + Msg // GetSigners returns the addrs of signers that must sign. // CONTRACT: All signatures must be present to be valid. @@ -36,21 +41,27 @@ type ( GetSignature() []byte } - // Tx defines the interface a transaction must fulfill. - Tx interface { - HasValidateBasic - + // HasMsgs defines an interface a transaction must fulfill. + HasMsgs interface { // GetMsgs gets the all the transaction's messages. GetMsgs() []Msg } + // Tx defines an interface a transaction must fulfill. + Tx interface { + HasMsgs + + // GetMsgsV2 gets the transaction's messages as google.golang.org/protobuf/proto.Message's. + GetMsgsV2() ([]protov2.Message, error) + } + // FeeTx defines the interface to be implemented by Tx to use the FeeDecorators FeeTx interface { Tx GetGas() uint64 GetFee() Coins - FeePayer() AccAddress - FeeGranter() AccAddress + FeePayer() []byte + FeeGranter() string } // TxWithMemo must have GetMemo() method to use ValidateMemoDecorator @@ -84,7 +95,11 @@ type TxDecoder func(txBytes []byte) (Tx, error) type TxEncoder func(tx Tx) ([]byte, error) // MsgTypeURL returns the TypeURL of a `sdk.Msg`. -func MsgTypeURL(msg Msg) string { +func MsgTypeURL(msg proto.Message) string { + if m, ok := msg.(protov2.Message); ok { + return "/" + string(m.ProtoReflect().Descriptor().FullName()) + } + return "/" + proto.MessageName(msg) } diff --git a/types/tx_msg_test.go b/types/tx_msg_test.go index ab12c4554639..6843af7d352f 100644 --- a/types/tx_msg_test.go +++ b/types/tx_msg_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/suite" + "google.golang.org/protobuf/types/known/anypb" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/testutil/testdata" @@ -31,6 +32,7 @@ func (s *testMsgSuite) TestMsg() { func (s *testMsgSuite) TestMsgTypeURL() { s.Require().Equal("/testpb.TestMsg", sdk.MsgTypeURL(new(testdata.TestMsg))) + s.Require().Equal("/google.protobuf.Any", sdk.MsgTypeURL(&anypb.Any{})) } func (s *testMsgSuite) TestGetMsgFromTypeURL() { diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 9256f825d135..f5b33fe6e4e8 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -119,8 +119,10 @@ func TestAnteHandlerSigErrors(t *testing.T) { require.NoError(t, err) // tx.GetSigners returns addresses in correct order: addr1, addr2, addr3 - expectedSigners := []sdk.AccAddress{addr0, addr1, addr2} - require.Equal(t, expectedSigners, tx.GetSigners()) + expectedSigners := [][]byte{addr0, addr1, addr2} + signers, err := tx.GetSigners() + require.NoError(t, err) + require.Equal(t, expectedSigners, signers) return TestCaseArgs{ accNums: accNums, diff --git a/x/auth/ante/basic.go b/x/auth/ante/basic.go index 8d335fc32b01..750824570ac4 100644 --- a/x/auth/ante/basic.go +++ b/x/auth/ante/basic.go @@ -31,8 +31,10 @@ func (vbd ValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulat return next(ctx, tx, simulate) } - if err := tx.ValidateBasic(); err != nil { - return ctx, err + if validateBasic, ok := tx.(sdk.HasValidateBasic); ok { + if err := validateBasic.ValidateBasic(); err != nil { + return ctx, err + } } return next(ctx, tx, simulate) @@ -108,7 +110,12 @@ func (cgts ConsumeTxSizeGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim } n := len(sigs) - for i, signer := range sigTx.GetSigners() { + signers, err := sigTx.GetSigners() + if err != nil { + return sdk.Context{}, err + } + + for i, signer := range signers { // if signature is already filled in, no need to simulate gas cost if i < n && !isIncompleteSignature(sigs[i].Data) { continue diff --git a/x/auth/ante/expected_keepers.go b/x/auth/ante/expected_keepers.go index 99f2dd8dc6ae..1fec5fdf1712 100644 --- a/x/auth/ante/expected_keepers.go +++ b/x/auth/ante/expected_keepers.go @@ -3,6 +3,7 @@ package ante import ( "context" + "cosmossdk.io/core/address" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -14,6 +15,7 @@ type AccountKeeper interface { GetAccount(ctx context.Context, addr sdk.AccAddress) sdk.AccountI SetAccount(ctx context.Context, acc sdk.AccountI) GetModuleAddress(moduleName string) sdk.AccAddress + AddressCodec() address.Codec } // FeegrantKeeper defines the expected feegrant keeper. diff --git a/x/auth/ante/fee.go b/x/auth/ante/fee.go index c7404a5d6ed0..b6131d59e1fc 100644 --- a/x/auth/ante/fee.go +++ b/x/auth/ante/fee.go @@ -1,6 +1,7 @@ package ante import ( + "bytes" "fmt" errorsmod "cosmossdk.io/errors" @@ -85,17 +86,22 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee // if feegranter set deduct fee from feegranter account. // this works with only when feegrant enabled. - if feeGranter != nil { + if feeGranter != "" { + feeGranterAddr, err := sdk.AccAddressFromBech32(feeGranter) + if err != nil { + return err + } + if dfd.feegrantKeeper == nil { return sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled") - } else if !feeGranter.Equals(feePayer) { - err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, sdkTx.GetMsgs()) + } else if !bytes.Equal(feeGranterAddr, feePayer) { + err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranterAddr, feePayer, fee, sdkTx.GetMsgs()) if err != nil { return errorsmod.Wrapf(err, "%s does not allow to pay fees for %s", feeGranter, feePayer) } } - deductFeesFrom = feeGranter + deductFeesFrom = feeGranterAddr } deductFeesFromAcc := dfd.accountKeeper.GetAccount(ctx, deductFeesFrom) @@ -115,7 +121,7 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee sdk.NewEvent( sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fee.String()), - sdk.NewAttribute(sdk.AttributeKeyFeePayer, deductFeesFrom.String()), + sdk.NewAttribute(sdk.AttributeKeyFeePayer, sdk.AccAddress(deductFeesFrom).String()), ), } ctx.EventManager().EmitEvents(events) diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index 16e042c0e9a1..7cd4e5cf2dce 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -9,6 +9,7 @@ import ( "google.golang.org/protobuf/types/known/anypb" errorsmod "cosmossdk.io/errors" + storetypes "cosmossdk.io/store/types" txsigning "cosmossdk.io/x/tx/signing" @@ -69,9 +70,20 @@ func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b if err != nil { return ctx, err } - signers := sigTx.GetSigners() + signers, err := sigTx.GetSigners() + if err != nil { + return sdk.Context{}, err + } + + signerStrs := make([]string, len(signers)) for i, pk := range pubkeys { + var err error + signerStrs[i], err = spkd.ak.AddressCodec().BytesToString(signers[i]) + if err != nil { + return sdk.Context{}, err + } + // PublicKey was omitted from slice since it has already been set in context if pk == nil { if !simulate { @@ -82,7 +94,7 @@ func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b // Only make check if simulate=false if !simulate && !bytes.Equal(pk.Address(), signers[i]) { return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidPubKey, - "pubKey does not match signer address %s with signer index: %d", signers[i], i) + "pubKey does not match signer address %s with signer index: %d", signerStrs[i], i) } acc, err := GetSignerAcc(ctx, spkd.ak, signers[i]) @@ -112,7 +124,7 @@ func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b var events sdk.Events for i, sig := range sigs { events = append(events, sdk.NewEvent(sdk.EventTypeTx, - sdk.NewAttribute(sdk.AttributeKeyAccountSequence, fmt.Sprintf("%s/%d", signers[i], sig.Sequence)), + sdk.NewAttribute(sdk.AttributeKeyAccountSequence, fmt.Sprintf("%s/%d", signerStrs[i], sig.Sequence)), )) sigBzs, err := signatureDataToBz(sig.Data) @@ -165,10 +177,13 @@ func (sgcd SigGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula // stdSigs contains the sequence number, account number, and signatures. // When simulating, this would just be a 0-length slice. - signerAddrs := sigTx.GetSigners() + signers, err := sigTx.GetSigners() + if err != nil { + return ctx, err + } for i, sig := range sigs { - signerAcc, err := GetSignerAcc(ctx, sgcd.ak, signerAddrs[i]) + signerAcc, err := GetSignerAcc(ctx, sgcd.ak, signers[i]) if err != nil { return ctx, err } @@ -250,15 +265,18 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul return ctx, err } - signerAddrs := sigTx.GetSigners() + signers, err := sigTx.GetSigners() + if err != nil { + return ctx, err + } // check that signer length and signature length are the same - if len(sigs) != len(signerAddrs) { - return ctx, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signerAddrs), len(sigs)) + if len(sigs) != len(signers) { + return ctx, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signers), len(sigs)) } for i, sig := range sigs { - acc, err := GetSignerAcc(ctx, svd.ak, signerAddrs[i]) + acc, err := GetSignerAcc(ctx, svd.ak, signers[i]) if err != nil { return ctx, err } @@ -349,8 +367,13 @@ func (isd IncrementSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim } // increment sequence of all signers - for _, addr := range sigTx.GetSigners() { - acc := isd.ak.GetAccount(ctx, addr) + signers, err := sigTx.GetSigners() + if err != nil { + return sdk.Context{}, err + } + + for _, signer := range signers { + acc := isd.ak.GetAccount(ctx, signer) if err := acc.SetSequence(acc.GetSequence() + 1); err != nil { panic(err) } @@ -516,10 +539,10 @@ func signatureDataToBz(data signing.SignatureData) ([][]byte, error) { sigs = append(sigs, nestedSigs...) } - multisig := cryptotypes.MultiSignature{ + multiSignature := cryptotypes.MultiSignature{ Signatures: sigs, } - aggregatedSig, err := multisig.Marshal() + aggregatedSig, err := multiSignature.Marshal() if err != nil { return nil, err } diff --git a/x/auth/client/cli/suite_test.go b/x/auth/client/cli/suite_test.go index 4fbe10635333..64a5b6e7ae30 100644 --- a/x/auth/client/cli/suite_test.go +++ b/x/auth/client/cli/suite_test.go @@ -7,12 +7,13 @@ import ( "strings" "testing" - "cosmossdk.io/core/address" "cosmossdk.io/math" abci "github.com/cometbft/cometbft/abci/types" rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" "github.com/stretchr/testify/suite" + "cosmossdk.io/core/address" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" addresscodec "github.com/cosmos/cosmos-sdk/codec/address" @@ -385,7 +386,7 @@ func (s *CLITestSuite) TestCLISendGenerateSignAndBroadcast() { // Test validate-signatures res, err := authtestutil.TxValidateSignaturesExec(s.clientCtx, unsignedTxFile.Name()) s.Require().EqualError(err, "signatures validation failed") - s.Require().True(strings.Contains(res.String(), fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n\n", s.val.String()))) + s.Require().Contains(res.String(), fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n\n", s.val.String())) // Test sign @@ -409,7 +410,9 @@ func (s *CLITestSuite) TestCLISendGenerateSignAndBroadcast() { sigs, err = txBuilder.GetTx().GetSignaturesV2() s.Require().NoError(err) s.Require().Equal(1, len(sigs)) - s.Require().Equal(s.val.String(), txBuilder.GetTx().GetSigners()[0].String()) + signers, err := txBuilder.GetTx().GetSigners() + s.Require().NoError(err) + s.Require().Equal([]byte(s.val), signers[0]) // Write the output to disk signedTxFile := testutil.WriteToNewTempFile(s.T(), signedTx.String()) @@ -922,7 +925,9 @@ func (s *CLITestSuite) TestSignWithMultiSignersAminoJSON() { ) txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10)))) txBuilder.SetGasLimit(testdata.NewTestGasLimit() * 2) - s.Require().Equal([]sdk.AccAddress{val0, val1}, txBuilder.GetTx().GetSigners()) + signers, err := txBuilder.GetTx().GetSigners() + s.Require().NoError(err) + s.Require().Equal([][]byte{val0, val1}, signers) // Write the unsigned tx into a file. txJSON, err := s.clientCtx.TxConfig.TxJSONEncoder()(txBuilder.GetTx()) diff --git a/x/auth/client/cli/validate_sigs.go b/x/auth/client/cli/validate_sigs.go index 42bc4fe276d4..4d599218d378 100644 --- a/x/auth/client/cli/validate_sigs.go +++ b/x/auth/client/cli/validate_sigs.go @@ -1,6 +1,7 @@ package cli import ( + "bytes" "fmt" "github.com/spf13/cobra" @@ -65,11 +66,20 @@ func printAndValidateSigs( ) bool { sigTx := tx.(authsigning.SigVerifiableTx) signModeHandler := clientCtx.TxConfig.SignModeHandler() + addrCdc := clientCtx.TxConfig.SigningContext().AddressCodec() cmd.Println("Signers:") - signers := sigTx.GetSigners() + signers, err := sigTx.GetSigners() + if err != nil { + panic(err) + } + for i, signer := range signers { - cmd.Printf(" %v: %v\n", i, signer.String()) + signerStr, err := addrCdc.BytesToString(signer) + if err != nil { + panic(err) + } + cmd.Printf(" %v: %v\n", i, signerStr) } success := true @@ -93,7 +103,7 @@ func printAndValidateSigs( sigSanity = "OK" ) - if i >= len(signers) || !sigAddr.Equals(signers[i]) { + if i >= len(signers) || !bytes.Equal(sigAddr, signers[i]) { sigSanity = "ERROR: signature does not match its respective signer" success = false } diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index 7a3cf8863618..a2e829641f1f 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -48,7 +48,11 @@ func SignTx(txFactory tx.Factory, clientCtx client.Context, name string, txBuild return err } addr := sdk.AccAddress(pubKey.Address()) - if !isTxSigner(addr, txBuilder.GetTx().GetSigners()) { + signers, err := txBuilder.GetTx().GetSigners() + if err != nil { + return err + } + if !isTxSigner(addr, signers) { return fmt.Errorf("%s: %s", errors.ErrorInvalidSigner, name) } if !offline { @@ -75,7 +79,12 @@ func SignTxWithSignerAddress(txFactory tx.Factory, clientCtx client.Context, add } // check whether the address is a signer - if !isTxSigner(addr, txBuilder.GetTx().GetSigners()) { + signers, err := txBuilder.GetTx().GetSigners() + if err != nil { + return err + } + + if !isTxSigner(addr, signers) { return fmt.Errorf("%s: %s", errors.ErrorInvalidSigner, name) } @@ -189,9 +198,9 @@ func ParseQueryResponse(bz []byte) (sdk.SimulationResponse, error) { return simRes, nil } -func isTxSigner(user sdk.AccAddress, signers []sdk.AccAddress) bool { +func isTxSigner(user []byte, signers [][]byte) bool { for _, s := range signers { - if bytes.Equal(user.Bytes(), s.Bytes()) { + if bytes.Equal(user, s) { return true } } diff --git a/x/auth/keeper/keeper.go b/x/auth/keeper/keeper.go index 18240beb25e2..8e4766db7a90 100644 --- a/x/auth/keeper/keeper.go +++ b/x/auth/keeper/keeper.go @@ -7,11 +7,12 @@ import ( "cosmossdk.io/collections" - "cosmossdk.io/core/address" - "cosmossdk.io/core/store" errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" + "cosmossdk.io/core/address" + "cosmossdk.io/core/store" + "github.com/cosmos/cosmos-sdk/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/auth/signing/sig_verifiable_tx.go b/x/auth/signing/sig_verifiable_tx.go index 1686ab93bd32..7aa05219f1cd 100644 --- a/x/auth/signing/sig_verifiable_tx.go +++ b/x/auth/signing/sig_verifiable_tx.go @@ -11,7 +11,7 @@ import ( // handlers. type SigVerifiableTx interface { types.Tx - GetSigners() []types.AccAddress + GetSigners() ([][]byte, error) GetPubKeys() ([]cryptotypes.PubKey, error) // If signer already has pubkey in context, this list will have nil in its place GetSignaturesV2() ([]signing.SignatureV2, error) } @@ -25,4 +25,5 @@ type Tx interface { types.FeeTx tx.TipTx types.TxWithTimeoutHeight + types.HasValidateBasic } diff --git a/x/auth/tx/aux_test.go b/x/auth/tx/aux_test.go index a0f4abf74efd..6f461c246c74 100644 --- a/x/auth/tx/aux_test.go +++ b/x/auth/tx/aux_test.go @@ -163,7 +163,7 @@ func TestBuilderWithAux(t *testing.T) { require.NoError(t, err) tx, err := txConfig.TxDecoder()(txBz) require.NoError(t, err) - require.Equal(t, tx.(sdk.FeeTx).FeePayer(), feepayerAddr) + require.Equal(t, tx.(sdk.FeeTx).FeePayer(), []byte(feepayerAddr)) require.Equal(t, tx.(sdk.FeeTx).GetFee(), fee) require.Equal(t, tx.(sdk.FeeTx).GetGas(), gas) require.Equal(t, tip, tx.(txtypes.TipTx).GetTip()) diff --git a/x/auth/tx/builder.go b/x/auth/tx/builder.go index d9452a170a7f..7cd594235873 100644 --- a/x/auth/tx/builder.go +++ b/x/auth/tx/builder.go @@ -1,9 +1,14 @@ package tx import ( + "bytes" + "fmt" + "github.com/cosmos/gogoproto/proto" + protov2 "google.golang.org/protobuf/proto" errorsmod "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -32,6 +37,9 @@ type wrapper struct { authInfoBz []byte txBodyHasUnknownNonCriticals bool + + signers [][]byte + msgsV2 []protov2.Message } var ( @@ -52,7 +60,7 @@ type ExtensionOptionsTxBuilder interface { } func newBuilder(cdc codec.Codec) *wrapper { - return &wrapper{ + w := &wrapper{ cdc: cdc, tx: &tx.Tx{ Body: &tx.TxBody{}, @@ -61,14 +69,47 @@ func newBuilder(cdc codec.Codec) *wrapper { }, }, } + return w } func (w *wrapper) GetMsgs() []sdk.Msg { return w.tx.GetMsgs() } +func (w *wrapper) GetMsgsV2() ([]protov2.Message, error) { + if w.msgsV2 == nil { + err := w.initSignersAndMsgsV2() + if err != nil { + return nil, err + } + } + + return w.msgsV2, nil +} + func (w *wrapper) ValidateBasic() error { - return w.tx.ValidateBasic() + if w.tx == nil { + return fmt.Errorf("bad Tx") + } + + if err := w.tx.ValidateBasic(); err != nil { + return err + } + + sigs := w.tx.Signatures + signers, err := w.GetSigners() + if err != nil { + return err + } + + if len(sigs) != len(signers) { + return errorsmod.Wrapf( + sdkerrors.ErrUnauthorized, + "wrong number of signers; expected %d, got %d", len(signers), len(sigs), + ) + } + + return nil } func (w *wrapper) getBodyBytes() []byte { @@ -103,8 +144,20 @@ func (w *wrapper) getAuthInfoBytes() []byte { return w.authInfoBz } -func (w *wrapper) GetSigners() []sdk.AccAddress { - return w.tx.GetSigners() +func (w *wrapper) initSignersAndMsgsV2() error { + var err error + w.signers, w.msgsV2, err = w.tx.GetSigners(w.cdc) + return err +} + +func (w *wrapper) GetSigners() ([][]byte, error) { + if w.signers == nil { + err := w.initSignersAndMsgsV2() + if err != nil { + return nil, err + } + } + return w.signers, nil } func (w *wrapper) GetPubKeys() ([]cryptotypes.PubKey, error) { @@ -138,21 +191,31 @@ func (w *wrapper) GetFee() sdk.Coins { return w.tx.AuthInfo.Fee.Amount } -func (w *wrapper) FeePayer() sdk.AccAddress { +func (w *wrapper) FeePayer() []byte { feePayer := w.tx.AuthInfo.Fee.Payer if feePayer != "" { - return sdk.MustAccAddressFromBech32(feePayer) + feePayerAddr, err := w.cdc.InterfaceRegistry().SigningContext().AddressCodec().StringToBytes(feePayer) + if err != nil { + panic(err) + } + return feePayerAddr } + // use first signer as default if no payer specified - return w.GetSigners()[0] + signers, err := w.GetSigners() + if err != nil { + return nil + } + + return signers[0] } -func (w *wrapper) FeeGranter() sdk.AccAddress { - feePayer := w.tx.AuthInfo.Fee.Granter - if feePayer != "" { - return sdk.MustAccAddressFromBech32(feePayer) +func (w *wrapper) FeeGranter() string { + feeGranter := w.tx.AuthInfo.Fee.Granter + if feeGranter != "" { + return feeGranter } - return nil + return "" } func (w *wrapper) GetTip() *tx.Tip { @@ -215,6 +278,10 @@ func (w *wrapper) SetMsgs(msgs ...sdk.Msg) error { // set bodyBz to nil because the cached bodyBz no longer matches tx.Body w.bodyBz = nil + // reset signers and msgsV2 + w.signers = nil + w.msgsV2 = nil + return nil } @@ -292,12 +359,12 @@ func (w *wrapper) SetSignatures(signatures ...signing.SignatureV2) error { for i, sig := range signatures { var modeInfo *tx.ModeInfo modeInfo, rawSigs[i] = SignatureDataToModeInfoAndSig(sig.Data) - any, err := codectypes.NewAnyWithValue(sig.PubKey) + pubKey, err := codectypes.NewAnyWithValue(sig.PubKey) if err != nil { return err } signerInfos[i] = &tx.SignerInfo{ - PublicKey: any, + PublicKey: pubKey, ModeInfo: modeInfo, Sequence: sig.Sequence, } @@ -316,8 +383,13 @@ func (w *wrapper) setSignerInfos(infos []*tx.SignerInfo) { } func (w *wrapper) setSignerInfoAtIndex(index int, info *tx.SignerInfo) { + signers, err := w.GetSigners() + if err != nil { + panic(err) + } + if w.tx.AuthInfo.SignerInfos == nil { - w.tx.AuthInfo.SignerInfos = make([]*tx.SignerInfo, len(w.GetSigners())) + w.tx.AuthInfo.SignerInfos = make([]*tx.SignerInfo, len(signers)) } w.tx.AuthInfo.SignerInfos[index] = info @@ -330,8 +402,13 @@ func (w *wrapper) setSignatures(sigs [][]byte) { } func (w *wrapper) setSignatureAtIndex(index int, sig []byte) { + signers, err := w.GetSigners() + if err != nil { + panic(err) + } + if w.tx.Signatures == nil { - w.tx.Signatures = make([][]byte, len(w.GetSigners())) + w.tx.Signatures = make([][]byte, len(signers)) } w.tx.Signatures[index] = sig @@ -443,13 +520,25 @@ func (w *wrapper) AddAuxSignerData(data tx.AuxSignerData) error { for i, msgAny := range body.Messages { msgs[i] = msgAny.GetCachedValue().(sdk.Msg) } - w.SetMsgs(msgs...) + err = w.SetMsgs(msgs...) + if err != nil { + return err + } w.SetTip(data.GetSignDoc().GetTip()) // Get the aux signer's index in GetSigners. signerIndex := -1 - for i, signer := range w.GetSigners() { - if signer.String() == data.Address { + signers, err := w.GetSigners() + if err != nil { + return err + } + + for i, signer := range signers { + addrBz, err := w.cdc.InterfaceRegistry().SigningContext().AddressCodec().StringToBytes(data.Address) + if err != nil { + return err + } + if bytes.Equal(signer, addrBz) { signerIndex = i } } diff --git a/x/auth/tx/builder_test.go b/x/auth/tx/builder_test.go index 5aa19e5e6ef5..c817b1718d80 100644 --- a/x/auth/tx/builder_test.go +++ b/x/auth/tx/builder_test.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/legacy" + "github.com/cosmos/cosmos-sdk/codec/testutil" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" @@ -22,7 +23,7 @@ func TestTxBuilder(t *testing.T) { _, pubkey, addr := testdata.KeyTestPubAddr() marshaler := codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) - txBuilder := newBuilder(nil) + txBuilder := newBuilder(marshaler) memo := "testmemo" msgs := []sdk.Msg{testdata.NewTestMsg(addr)} @@ -139,7 +140,7 @@ func TestBuilderValidateBasic(t *testing.T) { // require to fail validation upon invalid fee badFeeAmount := testdata.NewTestFeeAmount() badFeeAmount[0].Amount = sdkmath.NewInt(-5) - txBuilder := newBuilder(nil) + txBuilder := newBuilder(testutil.CodecOptions{}.NewCodec()) var sig1, sig2 signing.SignatureV2 sig1 = signing.SignatureV2{ @@ -258,21 +259,21 @@ func TestBuilderFeePayer(t *testing.T) { cases := map[string]struct { txFeePayer sdk.AccAddress - expectedSigners []sdk.AccAddress - expectedPayer sdk.AccAddress + expectedSigners [][]byte + expectedPayer []byte }{ "no fee payer specified": { - expectedSigners: []sdk.AccAddress{addr1, addr2}, + expectedSigners: [][]byte{addr1, addr2}, expectedPayer: addr1, }, "secondary signer set as fee payer": { txFeePayer: addr2, - expectedSigners: []sdk.AccAddress{addr1, addr2}, + expectedSigners: [][]byte{addr1, addr2}, expectedPayer: addr2, }, "outside signer set as fee payer": { txFeePayer: addr3, - expectedSigners: []sdk.AccAddress{addr1, addr2, addr3}, + expectedSigners: [][]byte{addr1, addr2, addr3}, expectedPayer: addr3, }, } @@ -280,7 +281,7 @@ func TestBuilderFeePayer(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { // setup basic tx - txBuilder := newBuilder(nil) + txBuilder := newBuilder(testutil.CodecOptions{}.NewCodec()) err := txBuilder.SetMsgs(msgs...) require.NoError(t, err) txBuilder.SetGasLimit(200000) @@ -289,7 +290,9 @@ func TestBuilderFeePayer(t *testing.T) { // set fee payer txBuilder.SetFeePayer(tc.txFeePayer) // and check it updates fields properly - require.Equal(t, tc.expectedSigners, txBuilder.GetSigners()) + signers, err := txBuilder.GetSigners() + require.NoError(t, err) + require.Equal(t, tc.expectedSigners, signers) require.Equal(t, tc.expectedPayer, txBuilder.FeePayer()) }) } @@ -314,5 +317,5 @@ func TestBuilderFeeGranter(t *testing.T) { // set fee granter txBuilder.SetFeeGranter(addr1) - require.Equal(t, addr1, txBuilder.GetTx().FeeGranter()) + require.Equal(t, addr1.String(), txBuilder.GetTx().FeeGranter()) } diff --git a/x/auth/tx/config.go b/x/auth/tx/config.go index aa48b3bd8059..0a375ba1b05c 100644 --- a/x/auth/tx/config.go +++ b/x/auth/tx/config.go @@ -18,12 +18,13 @@ import ( ) type config struct { - handler *txsigning.HandlerMap - decoder sdk.TxDecoder - encoder sdk.TxEncoder - jsonDecoder sdk.TxDecoder - jsonEncoder sdk.TxEncoder - protoCodec codec.ProtoCodecMarshaler + handler *txsigning.HandlerMap + decoder sdk.TxDecoder + encoder sdk.TxEncoder + jsonDecoder sdk.TxDecoder + jsonEncoder sdk.TxEncoder + protoCodec codec.ProtoCodecMarshaler + signingContext *txsigning.Context } // ConfigOptions define the configuration of a TxConfig when calling NewTxConfigWithOptions. @@ -125,6 +126,7 @@ func NewTxConfigWithOptions(protoCodec codec.ProtoCodecMarshaler, configOptions panic(err) } } + txConfig.signingContext = opts.SigningContext lenSignModes := len(configOptions.EnabledSignModes) handlers := make([]txsigning.SignModeHandler, lenSignModes+len(opts.CustomSignModes)) @@ -201,3 +203,7 @@ func (g config) TxJSONEncoder() sdk.TxEncoder { func (g config) TxJSONDecoder() sdk.TxDecoder { return g.jsonDecoder } + +func (g config) SigningContext() *txsigning.Context { + return g.signingContext +} diff --git a/x/auth/tx/config/config.go b/x/auth/tx/config/config.go index 69629e14cd51..5d6ab319474b 100644 --- a/x/auth/tx/config/config.go +++ b/x/auth/tx/config/config.go @@ -10,8 +10,9 @@ import ( bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" txconfigv1 "cosmossdk.io/api/cosmos/tx/config/v1" - "cosmossdk.io/core/appmodule" "cosmossdk.io/depinject" + + "cosmossdk.io/core/appmodule" txsigning "cosmossdk.io/x/tx/signing" "cosmossdk.io/x/tx/signing/textual" authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec" diff --git a/x/auth/tx/config_test.go b/x/auth/tx/config_test.go index 0e1e44970f0c..ebfb3d628977 100644 --- a/x/auth/tx/config_test.go +++ b/x/auth/tx/config_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/codec/testutil" "github.com/cosmos/cosmos-sdk/std" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,7 +14,7 @@ import ( ) func TestGenerator(t *testing.T) { - interfaceRegistry := codectypes.NewInterfaceRegistry() + interfaceRegistry := testutil.CodecOptions{}.NewInterfaceRegistry() std.RegisterInterfaces(interfaceRegistry) interfaceRegistry.RegisterImplementations((*sdk.Msg)(nil), &testdata.TestMsg{}) protoCodec := codec.NewProtoCodec(interfaceRegistry) diff --git a/x/auth/tx/decoder.go b/x/auth/tx/decoder.go index 2bfd2fbe95e2..16253a4ba154 100644 --- a/x/auth/tx/decoder.go +++ b/x/auth/tx/decoder.go @@ -73,6 +73,7 @@ func DefaultTxDecoder(cdc codec.ProtoCodecMarshaler) sdk.TxDecoder { bodyBz: raw.BodyBytes, authInfoBz: raw.AuthInfoBytes, txBodyHasUnknownNonCriticals: txBodyHasUnknownNonCriticals, + cdc: cdc, }, nil } } @@ -87,7 +88,8 @@ func DefaultJSONTxDecoder(cdc codec.ProtoCodecMarshaler) sdk.TxDecoder { } return &wrapper{ - tx: &theTx, + tx: &theTx, + cdc: cdc, }, nil } } diff --git a/x/auth/tx/direct_aux.go b/x/auth/tx/direct_aux.go index ff09cfd2b81c..75671a0fc409 100644 --- a/x/auth/tx/direct_aux.go +++ b/x/auth/tx/direct_aux.go @@ -1,6 +1,7 @@ package tx import ( + "bytes" "fmt" errorsmod "cosmossdk.io/errors" @@ -51,11 +52,16 @@ func (signModeDirectAuxHandler) GetSignBytes( return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "got empty address in %s handler", signingtypes.SignMode_SIGN_MODE_DIRECT_AUX) } - feePayer := protoTx.FeePayer().String() + feePayer := protoTx.FeePayer() // Fee payer cannot use SIGN_MODE_DIRECT_AUX, because SIGN_MODE_DIRECT_AUX // does not sign over fees, which would create malleability issues. - if feePayer == data.Address { + addrBz, err := sdk.AccAddressFromBech32(data.Address) + if err != nil { + return nil, err + } + + if bytes.Equal(feePayer, addrBz) { return nil, sdkerrors.ErrUnauthorized.Wrapf("fee payer %s cannot sign with %s", feePayer, signingtypes.SignMode_SIGN_MODE_DIRECT_AUX) } diff --git a/x/auth/tx/direct_aux_test.go b/x/auth/tx/direct_aux_test.go index 27a5764dbefc..32f76b17fbb8 100644 --- a/x/auth/tx/direct_aux_test.go +++ b/x/auth/tx/direct_aux_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/testutil" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" @@ -18,7 +19,7 @@ import ( func TestDirectAuxHandler(t *testing.T) { privKey, pubkey, addr := testdata.KeyTestPubAddr() _, feePayerPubKey, feePayerAddr := testdata.KeyTestPubAddr() - interfaceRegistry := codectypes.NewInterfaceRegistry() + interfaceRegistry := testutil.CodecOptions{}.NewInterfaceRegistry() interfaceRegistry.RegisterImplementations((*sdk.Msg)(nil), &testdata.TestMsg{}) marshaler := codec.NewProtoCodec(interfaceRegistry) @@ -81,7 +82,7 @@ func TestDirectAuxHandler(t *testing.T) { t.Log("verify fee payer cannot use SIGN_MODE_DIRECT_AUX") _, err = modeHandler.GetSignBytes(signingtypes.SignMode_SIGN_MODE_DIRECT_AUX, feePayerSigningData, txBuilder.GetTx()) - require.EqualError(t, err, fmt.Sprintf("fee payer %s cannot sign with %s: unauthorized", feePayerAddr.String(), signingtypes.SignMode_SIGN_MODE_DIRECT_AUX)) + require.EqualError(t, err, fmt.Sprintf("fee payer %s cannot sign with %s: unauthorized", []byte(feePayerAddr), signingtypes.SignMode_SIGN_MODE_DIRECT_AUX)) t.Log("verify GetSignBytes with generating sign bytes by marshaling signDocDirectAux") signBytes, err := modeHandler.GetSignBytes(signingtypes.SignMode_SIGN_MODE_DIRECT_AUX, signingData, txBuilder.GetTx()) diff --git a/x/auth/tx/direct_test.go b/x/auth/tx/direct_test.go index 737deda61ffb..296f82008f88 100644 --- a/x/auth/tx/direct_test.go +++ b/x/auth/tx/direct_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/require" + protov2 "google.golang.org/protobuf/proto" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -156,8 +157,9 @@ func TestDirectModeHandler_nonDIRECT_MODE(t *testing.T) { type nonProtoTx int -func (npt *nonProtoTx) GetMsgs() []sdk.Msg { return nil } -func (npt *nonProtoTx) ValidateBasic() error { return nil } +func (npt *nonProtoTx) GetMsgs() []sdk.Msg { return nil } +func (npt *nonProtoTx) GetMsgsV2() ([]protov2.Message, error) { return nil, nil } +func (npt *nonProtoTx) ValidateBasic() error { return nil } var _ sdk.Tx = (*nonProtoTx)(nil) diff --git a/x/auth/tx/encoder.go b/x/auth/tx/encoder.go index e69b57ec8df5..e98106a89a82 100644 --- a/x/auth/tx/encoder.go +++ b/x/auth/tx/encoder.go @@ -36,11 +36,6 @@ func DefaultJSONTxEncoder(cdc codec.ProtoCodecMarshaler) sdk.TxEncoder { return cdc.MarshalJSON(txWrapper.tx) } - protoTx, ok := tx.(*txtypes.Tx) - if ok { - return cdc.MarshalJSON(protoTx) - } - return nil, fmt.Errorf("expected %T, got %T", &wrapper{}, tx) } } diff --git a/x/auth/tx/testutil/suite.go b/x/auth/tx/testutil/suite.go index d4f2cbd884bb..2d95ba6dcffa 100644 --- a/x/auth/tx/testutil/suite.go +++ b/x/auth/tx/testutil/suite.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/suite" signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" + "github.com/cosmos/cosmos-sdk/client" kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -74,8 +75,10 @@ func (s *TxConfigTestSuite) TestTxBuilderSetMsgs() { 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()) + signers, err := tx.GetSigners() + s.Require().NoError(err) + s.Require().Equal([][]byte{addr1, addr2}, signers) + s.Require().Equal([]byte(addr1), tx.FeePayer()) s.Require().Error(tx.ValidateBasic()) // should fail because of no signatures } @@ -127,7 +130,9 @@ func (s *TxConfigTestSuite) TestTxBuilderSetSignatures() { 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()) + signers, err := sigTx.GetSigners() + s.Require().NoError(err) + s.Require().Equal([][]byte{addr, msigAddr}, signers) s.Require().NoError(sigTx.ValidateBasic()) // sign transaction @@ -178,7 +183,9 @@ func (s *TxConfigTestSuite) TestTxBuilderSetSignatures() { 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()) + signers, err = sigTx.GetSigners() + s.Require().NoError(err) + s.Require().Equal([][]byte{addr, msigAddr}, signers) s.Require().NoError(sigTx.ValidateBasic()) } diff --git a/x/authz/keeper/keeper.go b/x/authz/keeper/keeper.go index 0177927113b6..8c1a11ec4851 100644 --- a/x/authz/keeper/keeper.go +++ b/x/authz/keeper/keeper.go @@ -1,6 +1,7 @@ package keeper import ( + "bytes" "context" "fmt" "strconv" @@ -30,13 +31,13 @@ const gasCostPerIteration = uint64(20) type Keeper struct { storeService corestoretypes.KVStoreService - cdc codec.BinaryCodec + cdc codec.Codec router baseapp.MessageRouter authKeeper authz.AccountKeeper } // NewKeeper constructs a message authorization Keeper -func NewKeeper(storeService corestoretypes.KVStoreService, cdc codec.BinaryCodec, router baseapp.MessageRouter, ak authz.AccountKeeper) Keeper { +func NewKeeper(storeService corestoretypes.KVStoreService, cdc codec.Codec, router baseapp.MessageRouter, ak authz.AccountKeeper) Keeper { return Keeper{ storeService: storeService, cdc: cdc, @@ -99,7 +100,11 @@ func (k Keeper) DispatchActions(ctx context.Context, grantee sdk.AccAddress, msg now := sdkCtx.BlockTime() for i, msg := range msgs { - signers := msg.GetSigners() + signers, _, err := k.cdc.GetMsgV1Signers(msg) + if err != nil { + return nil, err + } + if len(signers) != 1 { return nil, authz.ErrAuthorizationNumOfSigners } @@ -108,7 +113,7 @@ func (k Keeper) DispatchActions(ctx context.Context, grantee sdk.AccAddress, msg // If granter != grantee then check authorization.Accept, otherwise we // implicitly accept. - if !granter.Equals(grantee) { + if !bytes.Equal(granter, grantee) { skey := grantStoreKey(grantee, granter, sdk.MsgTypeURL(msg)) grant, found := k.getGrant(ctx, skey) diff --git a/x/gov/keeper/keeper.go b/x/gov/keeper/keeper.go index 2c520c2a8c9a..db95a0a89ad9 100644 --- a/x/gov/keeper/keeper.go +++ b/x/gov/keeper/keeper.go @@ -36,7 +36,7 @@ type Keeper struct { storeService corestoretypes.KVStoreService // The codec for binary encoding/decoding. - cdc codec.BinaryCodec + cdc codec.Codec // Legacy Proposal router legacyRouter v1beta1.Router @@ -72,7 +72,7 @@ func (k Keeper) GetAuthority() string { // // CONTRACT: the parameter Subspace must have the param key table already initialized func NewKeeper( - cdc codec.BinaryCodec, storeService corestoretypes.KVStoreService, authKeeper types.AccountKeeper, + cdc codec.Codec, storeService corestoretypes.KVStoreService, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper, distrKeeper types.DistributionKeeper, router baseapp.MessageRouter, config types.Config, authority string, ) *Keeper { diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index 032e800cd771..c6487b85379e 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -1,6 +1,7 @@ package keeper import ( + "bytes" "context" "errors" "fmt" @@ -47,14 +48,17 @@ func (keeper Keeper) SubmitProposal(ctx context.Context, messages []sdk.Msg, met } } - signers := msg.GetSigners() + signers, _, err := keeper.cdc.GetMsgV1Signers(msg) + if err != nil { + return v1.Proposal{}, err + } if len(signers) != 1 { return v1.Proposal{}, types.ErrInvalidSigner } // assert that the governance module account is the only signer of the messages - if !signers[0].Equals(keeper.GetGovernanceAccount(ctx).GetAddress()) { - return v1.Proposal{}, errorsmod.Wrapf(types.ErrInvalidSigner, signers[0].String()) + if !bytes.Equal(signers[0], keeper.GetGovernanceAccount(ctx).GetAddress()) { + return v1.Proposal{}, errorsmod.Wrapf(types.ErrInvalidSigner, sdk.AccAddress(signers[0]).String()) } // use the msg service router to see that there is a valid route for that message. diff --git a/x/group/keeper/keeper.go b/x/group/keeper/keeper.go index 63959f4c3294..f936af7f955c 100644 --- a/x/group/keeper/keeper.go +++ b/x/group/keeper/keeper.go @@ -79,6 +79,8 @@ type Keeper struct { router baseapp.MessageRouter config group.Config + + cdc codec.Codec } // NewKeeper creates a new group keeper. @@ -87,6 +89,7 @@ func NewKeeper(storeKey storetypes.StoreKey, cdc codec.Codec, router baseapp.Mes key: storeKey, router: router, accKeeper: accKeeper, + cdc: cdc, } groupTable, err := orm.NewAutoUInt64Table([2]byte{GroupTablePrefix}, GroupTableSeqPrefix, &group.GroupInfo{}, cdc) diff --git a/x/group/keeper/msg_server.go b/x/group/keeper/msg_server.go index d6980be4f293..22c33a48cd6e 100644 --- a/x/group/keeper/msg_server.go +++ b/x/group/keeper/msg_server.go @@ -575,7 +575,7 @@ func (k Keeper) SubmitProposal(goCtx context.Context, msg *group.MsgSubmitPropos } // Check that if the messages require signers, they are all equal to the given account address of group policy. - if err := ensureMsgAuthZ(msgs, groupPolicyAddr); err != nil { + if err := ensureMsgAuthZ(msgs, groupPolicyAddr, k.cdc); err != nil { return nil, err } diff --git a/x/group/keeper/proposal_executor.go b/x/group/keeper/proposal_executor.go index abc2d86d8ba2..8f2b9165f5aa 100644 --- a/x/group/keeper/proposal_executor.go +++ b/x/group/keeper/proposal_executor.go @@ -1,11 +1,13 @@ package keeper import ( + "bytes" "fmt" errorsmod "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/group" @@ -37,7 +39,7 @@ func (s Keeper) doExecuteMsgs(ctx sdk.Context, router baseapp.MessageRouter, pro } results := make([]sdk.Result, len(msgs)) - if err := ensureMsgAuthZ(msgs, groupPolicyAcc); err != nil { + if err := ensureMsgAuthZ(msgs, groupPolicyAcc, s.cdc); err != nil { return nil, err } for i, msg := range msgs { @@ -61,15 +63,20 @@ func (s Keeper) doExecuteMsgs(ctx sdk.Context, router baseapp.MessageRouter, pro // ensureMsgAuthZ checks that if a message requires signers that all of them // are equal to the given account address of group policy. -func ensureMsgAuthZ(msgs []sdk.Msg, groupPolicyAcc sdk.AccAddress) error { +func ensureMsgAuthZ(msgs []sdk.Msg, groupPolicyAcc sdk.AccAddress, cdc codec.Codec) error { for i := range msgs { // In practice, GetSigners() should return a non-empty array without // duplicates, so the code below is equivalent to: // `msgs[i].GetSigners()[0] == groupPolicyAcc` // but we prefer to loop through all GetSigners just to be sure. - for _, acct := range msgs[i].GetSigners() { - if !groupPolicyAcc.Equals(acct) { - return errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "msg does not have group policy authorization; expected %s, got %s", groupPolicyAcc.String(), acct.String()) + signers, _, err := cdc.GetMsgV1Signers(msgs[i]) + if err != nil { + return err + } + + for _, acct := range signers { + if !bytes.Equal(groupPolicyAcc, acct) { + return errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "msg does not have group policy authorization; expected %s, got %s", groupPolicyAcc.String(), acct) } } }