From 3ba1d996239cf1655119c8ce8f10a44bfce4f1ee Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Mon, 6 May 2024 14:44:11 +0200 Subject: [PATCH 01/14] add: simulate nested messages --- baseapp/abci_test.go | 120 +++- baseapp/baseapp.go | 62 ++ baseapp/testutil/messages.go | 25 +- baseapp/testutil/messages.pb.go | 997 ++++++++++++++++++++++++++++++-- baseapp/testutil/messages.proto | 29 +- baseapp/utils_test.go | 56 ++ 6 files changed, 1235 insertions(+), 54 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 9a3d6edd1682..47ff4a024f78 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -23,6 +23,7 @@ import ( protoio "github.com/cosmos/gogoproto/io" "github.com/cosmos/gogoproto/jsonpb" "github.com/cosmos/gogoproto/proto" + any "github.com/cosmos/gogoproto/types/any" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" @@ -33,7 +34,6 @@ import ( snapshottypes "cosmossdk.io/store/snapshots/types" storetypes "cosmossdk.io/store/types" "cosmossdk.io/x/auth/signing" - "github.com/cosmos/cosmos-sdk/baseapp" baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil" "github.com/cosmos/cosmos-sdk/baseapp/testutil/mock" @@ -758,6 +758,124 @@ func TestABCI_FinalizeBlock_MultiMsg(t *testing.T) { require.Equal(t, int64(2), msgCounter2) } +func TestABCI_Query_SimulateNestedMessagesTx(t *testing.T) { + gasConsumed := uint64(5) + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + newCtx = ctx.WithGasMeter(storetypes.NewGasMeter(gasConsumed)) + return + }) + } + suite := NewBaseAppSuite(t, anteOpt) + + _, err := suite.baseApp.InitChain(&abci.RequestInitChain{ + ConsensusParams: &cmtproto.ConsensusParams{}, + }) + require.NoError(t, err) + + baseapptestutil.RegisterNestedMessagesServer(suite.baseApp.MsgServiceRouter(), NesteMessgesServerImpl{}) + baseapptestutil.RegisterSendServer(suite.baseApp.MsgServiceRouter(), SendServerImpl{}) + + _, _, addr := testdata.KeyTestPubAddr() + _, _, toAddr := testdata.KeyTestPubAddr() + tests := []struct { + name string + nestedMsgs []*baseapptestutil.MsgSend + wantErr bool + }{ + { + name: "ok nested message", + nestedMsgs: []*baseapptestutil.MsgSend{ + { + From: addr.String(), + To: toAddr.String(), + Amount: "10000stake", + }, + }, + }, + { + name: "different signers", + nestedMsgs: []*baseapptestutil.MsgSend{ + { + From: toAddr.String(), + To: addr.String(), + Amount: "10000stake", + }, + }, + wantErr: true, + }, + { + name: "empty from", + nestedMsgs: []*baseapptestutil.MsgSend{ + { + From: "", + To: toAddr.String(), + Amount: "10000stake", + }, + }, + wantErr: true, + }, + { + name: "empty to", + nestedMsgs: []*baseapptestutil.MsgSend{ + { + From: addr.String(), + To: "", + Amount: "10000stake", + }, + }, + wantErr: true, + }, + { + name: "negative amount", + nestedMsgs: []*baseapptestutil.MsgSend{ + { + From: addr.String(), + To: toAddr.String(), + Amount: "-10000stake", + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + nestedMessages := make([]*any.Any, len(tt.nestedMsgs)) + for i, msg := range tt.nestedMsgs { + b, err := suite.cdc.Marshal(msg) + require.NoError(t, err) + nestedMessages[i] = &any.Any{ + TypeUrl: sdk.MsgTypeURL(msg), + Value: b, + } + } + msg := &baseapptestutil.MsgNestedMessages{ + Messages: nestedMessages, + Signer: addr.String(), + } + + builder := suite.txConfig.NewTxBuilder() + err = builder.SetMsgs(msg) + require.NoError(t, err) + setTxSignature(t, builder, 0) + tx := builder.GetTx() + + txBytes, err := suite.txConfig.TxEncoder()(tx) + require.Nil(t, err) + + _, result, err := suite.baseApp.Simulate(txBytes) + if tt.wantErr { + require.Error(t, err) + require.Nil(t, result) + } else { + require.NoError(t, err) + require.NotNil(t, result) + } + + }) + } +} + func TestABCI_Query_SimulateTx(t *testing.T) { gasConsumed := uint64(5) anteOpt := func(bapp *baseapp.BaseApp) { diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index ed25df52d362..16d6f046cc9f 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -13,9 +13,11 @@ import ( "github.com/cometbft/cometbft/crypto/tmhash" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-proto/anyutil" "github.com/cosmos/gogoproto/proto" "golang.org/x/exp/maps" protov2 "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" "cosmossdk.io/core/header" errorsmod "cosmossdk.io/errors" @@ -810,6 +812,10 @@ func (app *BaseApp) endBlock(ctx context.Context) (sdk.EndBlock, error) { return endblock, nil } +type HasNestedMsgs interface { + GetMsgs() ([]sdk.Msg, error) +} + // runTx processes a transaction within a given execution mode, encoded transaction // bytes, and the decoded transaction itself. All state transitions occur through // a cached Context depending on the mode provided. State only gets persisted @@ -954,6 +960,20 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res result, err = app.runMsgs(runMsgCtx, msgs, msgsV2, mode) } + if mode == execModeSimulate { + nestedMsgsContext, _ := app.cacheTxContext(ctx, txBytes) + for _, msg := range msgs { + msg, ok := msg.(HasNestedMsgs) + if !ok { + continue + } + nestedErr := app.simulateNestedMessages(nestedMsgsContext, msg) + if nestedErr != nil { + return gInfo, nil, anteEvents, nestedErr + } + } + } + // Run optional postHandlers (should run regardless of the execution result). // // Note: If the postHandler fails, we also revert the runMsgs state. @@ -1060,6 +1080,48 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, msgsV2 []protov2.Me }, nil } +// simulateNestedMessages simulates a message nested messages. +func (app *BaseApp) simulateNestedMessages(ctx sdk.Context, msg HasNestedMsgs) error { + msgs, err := msg.GetMsgs() + if err != nil { + return err + } + + if err := validateBasicTxMsgs(app.msgServiceRouter, msgs); err != nil { + return err + } + + msgsV2, err := app.msgsV1ToMsgsV2(msgs) + if err != nil { + return err + } + + _, err = app.runMsgs(ctx, msgs, msgsV2, execModeSimulate) + return err +} + +// msgsV1ToMsgsV2 transforms v1 messages into v2. +func (app *BaseApp) msgsV1ToMsgsV2(msgs []sdk.Msg) ([]protov2.Message, error) { + msgsV2 := make([]protov2.Message, len(msgs)) + for i, msg := range msgs { + gogoAny, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return nil, err + } + anyMsg := &anypb.Any{ + TypeUrl: gogoAny.TypeUrl, + Value: gogoAny.Value, + } + msgV2, err := anyutil.Unpack(anyMsg, app.cdc.InterfaceRegistry().SigningContext().FileResolver(), app.cdc.InterfaceRegistry().SigningContext().TypeResolver()) + if err != nil { + return nil, err + } + msgsV2[i] = msgV2 + } + + return msgsV2, nil +} + // makeABCIData generates the Data field to be sent to ABCI Check/DeliverTx. func makeABCIData(msgResponses []*codectypes.Any) ([]byte, error) { return proto.Marshal(&sdk.TxMsgData{MsgResponses: msgResponses}) diff --git a/baseapp/testutil/messages.go b/baseapp/testutil/messages.go index a4b1cd9abbcb..bffce60ba976 100644 --- a/baseapp/testutil/messages.go +++ b/baseapp/testutil/messages.go @@ -2,7 +2,7 @@ package testutil import ( errorsmod "cosmossdk.io/errors" - + codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -16,10 +16,15 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &MsgCounter{}, &MsgCounter2{}, &MsgKeyValue{}, + &MsgNestedMessages{}, + &MsgSend{}, ) + msgservice.RegisterMsgServiceDesc(registry, &_Counter_serviceDesc) msgservice.RegisterMsgServiceDesc(registry, &_Counter2_serviceDesc) msgservice.RegisterMsgServiceDesc(registry, &_KeyValue_serviceDesc) + msgservice.RegisterMsgServiceDesc(registry, &_NestedMessages_serviceDesc) + msgservice.RegisterMsgServiceDesc(registry, &_Send_serviceDesc) codec.RegisterInterfaces(registry) } @@ -63,3 +68,21 @@ func (msg *MsgKeyValue) ValidateBasic() error { } return nil } + +func (msg *MsgNestedMessages) GetMsgs() ([]sdk.Msg, error) { + cdc := codectestutil.CodecOptions{}.NewCodec() + RegisterInterfaces(cdc.InterfaceRegistry()) + msgs := make([]sdk.Msg, len(msg.GetMessages())) + for i, m := range msg.GetMessages() { + mm, err := cdc.InterfaceRegistry().Resolve(m.TypeUrl) + if err != nil { + return nil, err + } + err = cdc.UnpackAny(m, &mm) + if err != nil { + return nil, err + } + msgs[i] = mm + } + return msgs, nil +} diff --git a/baseapp/testutil/messages.pb.go b/baseapp/testutil/messages.pb.go index 2884ff0f649a..da3421a020f9 100644 --- a/baseapp/testutil/messages.pb.go +++ b/baseapp/testutil/messages.pb.go @@ -6,11 +6,11 @@ package testutil import ( context "context" fmt "fmt" - _ "github.com/cosmos/cosmos-sdk/codec/types" _ "github.com/cosmos/cosmos-sdk/types/msgservice" _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" + any "github.com/cosmos/gogoproto/types/any" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -282,43 +282,240 @@ func (m *MsgCreateKeyValueResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgCreateKeyValueResponse proto.InternalMessageInfo +type MsgSend struct { + From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` + Amount string `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (m *MsgSend) Reset() { *m = MsgSend{} } +func (m *MsgSend) String() string { return proto.CompactTextString(m) } +func (*MsgSend) ProtoMessage() {} +func (*MsgSend) Descriptor() ([]byte, []int) { + return fileDescriptor_4dc296cbfe5ffcd5, []int{5} +} +func (m *MsgSend) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSend.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSend) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSend.Merge(m, src) +} +func (m *MsgSend) XXX_Size() int { + return m.Size() +} +func (m *MsgSend) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSend.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSend proto.InternalMessageInfo + +func (m *MsgSend) GetFrom() string { + if m != nil { + return m.From + } + return "" +} + +func (m *MsgSend) GetTo() string { + if m != nil { + return m.To + } + return "" +} + +func (m *MsgSend) GetAmount() string { + if m != nil { + return m.Amount + } + return "" +} + +type MsgSendResponse struct { +} + +func (m *MsgSendResponse) Reset() { *m = MsgSendResponse{} } +func (m *MsgSendResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSendResponse) ProtoMessage() {} +func (*MsgSendResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_4dc296cbfe5ffcd5, []int{6} +} +func (m *MsgSendResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSendResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSendResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSendResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSendResponse.Merge(m, src) +} +func (m *MsgSendResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSendResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSendResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSendResponse proto.InternalMessageInfo + +type MsgNestedMessages struct { + Messages []*any.Any `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` + Signer string `protobuf:"bytes,2,opt,name=signer,proto3" json:"signer,omitempty"` +} + +func (m *MsgNestedMessages) Reset() { *m = MsgNestedMessages{} } +func (m *MsgNestedMessages) String() string { return proto.CompactTextString(m) } +func (*MsgNestedMessages) ProtoMessage() {} +func (*MsgNestedMessages) Descriptor() ([]byte, []int) { + return fileDescriptor_4dc296cbfe5ffcd5, []int{7} +} +func (m *MsgNestedMessages) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgNestedMessages) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgNestedMessages.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgNestedMessages) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgNestedMessages.Merge(m, src) +} +func (m *MsgNestedMessages) XXX_Size() int { + return m.Size() +} +func (m *MsgNestedMessages) XXX_DiscardUnknown() { + xxx_messageInfo_MsgNestedMessages.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgNestedMessages proto.InternalMessageInfo + +func (m *MsgNestedMessages) GetMessages() []*any.Any { + if m != nil { + return m.Messages + } + return nil +} + +func (m *MsgNestedMessages) GetSigner() string { + if m != nil { + return m.Signer + } + return "" +} + +type MsgCreateNestedMessagesResponse struct { +} + +func (m *MsgCreateNestedMessagesResponse) Reset() { *m = MsgCreateNestedMessagesResponse{} } +func (m *MsgCreateNestedMessagesResponse) String() string { return proto.CompactTextString(m) } +func (*MsgCreateNestedMessagesResponse) ProtoMessage() {} +func (*MsgCreateNestedMessagesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_4dc296cbfe5ffcd5, []int{8} +} +func (m *MsgCreateNestedMessagesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreateNestedMessagesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreateNestedMessagesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgCreateNestedMessagesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreateNestedMessagesResponse.Merge(m, src) +} +func (m *MsgCreateNestedMessagesResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgCreateNestedMessagesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreateNestedMessagesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreateNestedMessagesResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*MsgCounter)(nil), "MsgCounter") proto.RegisterType((*MsgCounter2)(nil), "MsgCounter2") proto.RegisterType((*MsgCreateCounterResponse)(nil), "MsgCreateCounterResponse") proto.RegisterType((*MsgKeyValue)(nil), "MsgKeyValue") proto.RegisterType((*MsgCreateKeyValueResponse)(nil), "MsgCreateKeyValueResponse") + proto.RegisterType((*MsgSend)(nil), "MsgSend") + proto.RegisterType((*MsgSendResponse)(nil), "MsgSendResponse") + proto.RegisterType((*MsgNestedMessages)(nil), "MsgNestedMessages") + proto.RegisterType((*MsgCreateNestedMessagesResponse)(nil), "MsgCreateNestedMessagesResponse") } func init() { proto.RegisterFile("messages.proto", fileDescriptor_4dc296cbfe5ffcd5) } var fileDescriptor_4dc296cbfe5ffcd5 = []byte{ - // 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, + // 535 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x93, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0xc6, 0xeb, 0xa4, 0x6d, 0x92, 0x49, 0x48, 0xd3, 0x55, 0x04, 0x8e, 0x91, 0x4c, 0xc8, 0x01, + 0x45, 0x95, 0xba, 0x06, 0x73, 0x4b, 0xc5, 0x01, 0x2a, 0x54, 0x10, 0x0a, 0x45, 0xae, 0xc4, 0xa1, + 0x97, 0xca, 0x49, 0x26, 0x9b, 0x90, 0x78, 0x37, 0xf2, 0xae, 0x2b, 0xe5, 0xca, 0x13, 0xf0, 0x28, + 0x3c, 0x06, 0xc7, 0x1e, 0x39, 0xa2, 0xe4, 0xc0, 0x6b, 0x20, 0xaf, 0xff, 0xb4, 0x14, 0x02, 0x9c, + 0x38, 0xed, 0xcc, 0xac, 0x77, 0x7e, 0xb3, 0xfb, 0x7d, 0x86, 0x7a, 0x80, 0x52, 0xfa, 0x0c, 0x25, + 0x5d, 0x84, 0x42, 0x09, 0xab, 0xc9, 0x04, 0x13, 0x3a, 0x74, 0xe2, 0x28, 0xad, 0xb6, 0x98, 0x10, + 0x6c, 0x8e, 0x8e, 0xce, 0x06, 0xd1, 0xd8, 0xf1, 0xf9, 0x32, 0xdd, 0xba, 0x37, 0x14, 0x32, 0x10, + 0xd2, 0x09, 0x24, 0x73, 0x2e, 0x9f, 0xc4, 0x4b, 0xb2, 0xd1, 0x91, 0x00, 0x7d, 0xc9, 0x8e, 0x45, + 0xc4, 0x15, 0x86, 0xc4, 0x84, 0xd2, 0x30, 0x09, 0x4d, 0xa3, 0x6d, 0x74, 0x8b, 0x5e, 0x96, 0x92, + 0x47, 0xb0, 0x37, 0xf6, 0xa7, 0xf3, 0x0b, 0xc1, 0x2f, 0x26, 0x3e, 0x1f, 0xcd, 0x31, 0x34, 0x0b, + 0x6d, 0xa3, 0x5b, 0xf6, 0xee, 0xc4, 0xe5, 0x53, 0xfe, 0x2a, 0x29, 0x92, 0xbb, 0xb0, 0x2b, 0xa7, + 0x8c, 0x63, 0x68, 0x16, 0xdb, 0x46, 0xb7, 0xe2, 0xa5, 0x59, 0xaf, 0xfa, 0xf1, 0xfb, 0xe7, 0x83, + 0x34, 0xe9, 0x28, 0xa8, 0x5e, 0x43, 0xdd, 0xff, 0x45, 0xb5, 0xc0, 0x8c, 0xa9, 0x21, 0xfa, 0x0a, + 0x53, 0xb6, 0x87, 0x72, 0x21, 0xb8, 0xc4, 0xce, 0xb9, 0x9e, 0xe8, 0x0d, 0x2e, 0xdf, 0xfb, 0xf3, + 0x08, 0x49, 0x03, 0x8a, 0x33, 0x5c, 0xea, 0x69, 0x6a, 0x5e, 0x1c, 0x92, 0x26, 0xec, 0x5c, 0xc6, + 0x5b, 0x9a, 0x5f, 0xf3, 0x92, 0xe4, 0xdf, 0xb8, 0xf7, 0xa1, 0x95, 0x73, 0x33, 0x42, 0x0e, 0x7e, + 0x07, 0xa5, 0xbe, 0x64, 0x67, 0xc8, 0x47, 0x84, 0xc0, 0xf6, 0x38, 0x14, 0x81, 0xa6, 0x56, 0x3c, + 0x1d, 0x93, 0x3a, 0x14, 0x94, 0xd0, 0xcc, 0x8a, 0x57, 0x50, 0x22, 0x06, 0xfa, 0x41, 0x3c, 0x7b, + 0x06, 0x4c, 0xb2, 0x5e, 0x25, 0x06, 0xea, 0x23, 0x9d, 0x7d, 0xd8, 0x4b, 0x3b, 0xe6, 0x90, 0x0f, + 0xb0, 0xdf, 0x97, 0xec, 0x2d, 0x4a, 0x85, 0xa3, 0x7e, 0xea, 0x24, 0xf2, 0x18, 0xca, 0x99, 0xab, + 0x4c, 0xa3, 0x5d, 0xec, 0x56, 0xdd, 0x26, 0x4d, 0x0c, 0x44, 0x33, 0x03, 0xd1, 0xe7, 0x7c, 0xe9, + 0xe5, 0x5f, 0xdd, 0xb8, 0x6d, 0x61, 0xf3, 0x6d, 0x1f, 0xc2, 0x83, 0xfc, 0xb6, 0x3f, 0x13, 0xb3, + 0x71, 0xdc, 0x97, 0x50, 0xca, 0x0c, 0xd7, 0x83, 0xc6, 0x6b, 0x3e, 0x0c, 0x31, 0x40, 0xae, 0xb2, + 0x5a, 0x95, 0x5e, 0x9b, 0xc3, 0x6a, 0xd1, 0x4d, 0x9a, 0xb9, 0x27, 0x50, 0xce, 0x2d, 0x74, 0xf4, + 0x9b, 0x3e, 0xb5, 0x1b, 0x7d, 0xdc, 0x3f, 0x35, 0x3a, 0x82, 0x72, 0xae, 0xbc, 0x03, 0xc5, 0x33, + 0x54, 0xc9, 0xd9, 0xac, 0x68, 0x59, 0x74, 0xa3, 0x80, 0xee, 0x01, 0x6c, 0x6b, 0xf5, 0x3a, 0xe9, + 0x5a, 0xa6, 0xe9, 0xeb, 0x5b, 0x0d, 0x7a, 0x4b, 0x07, 0xf7, 0x14, 0xea, 0xb7, 0x44, 0x78, 0x06, + 0x3b, 0xc7, 0x13, 0x1c, 0xce, 0x08, 0xa1, 0xbf, 0x28, 0x64, 0xb5, 0xe9, 0x5f, 0x5e, 0xf2, 0xc5, + 0xc9, 0x97, 0x95, 0x6d, 0x5c, 0xad, 0x6c, 0xe3, 0xdb, 0xca, 0x36, 0x3e, 0xad, 0xed, 0xad, 0xab, + 0xb5, 0xbd, 0xf5, 0x75, 0x6d, 0x6f, 0x9d, 0x1f, 0xb2, 0xa9, 0x9a, 0x44, 0x03, 0x3a, 0x14, 0x81, + 0x93, 0xfe, 0xfb, 0xc9, 0x72, 0x28, 0x47, 0x33, 0x67, 0xe0, 0x4b, 0xf4, 0x17, 0x0b, 0x47, 0xa1, + 0x54, 0x91, 0x9a, 0xce, 0x07, 0xbb, 0x5a, 0xf2, 0xa7, 0x3f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x12, + 0x9a, 0xa4, 0x74, 0x69, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -545,6 +742,150 @@ var _KeyValue_serviceDesc = grpc.ServiceDesc{ Metadata: "messages.proto", } +// SendClient is the client API for Send service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type SendClient interface { + Send(ctx context.Context, in *MsgSend, opts ...grpc.CallOption) (*MsgSendResponse, error) +} + +type sendClient struct { + cc grpc1.ClientConn +} + +func NewSendClient(cc grpc1.ClientConn) SendClient { + return &sendClient{cc} +} + +func (c *sendClient) Send(ctx context.Context, in *MsgSend, opts ...grpc.CallOption) (*MsgSendResponse, error) { + out := new(MsgSendResponse) + err := c.cc.Invoke(ctx, "/Send/Send", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SendServer is the server API for Send service. +type SendServer interface { + Send(context.Context, *MsgSend) (*MsgSendResponse, error) +} + +// UnimplementedSendServer can be embedded to have forward compatible implementations. +type UnimplementedSendServer struct { +} + +func (*UnimplementedSendServer) Send(ctx context.Context, req *MsgSend) (*MsgSendResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Send not implemented") +} + +func RegisterSendServer(s grpc1.Server, srv SendServer) { + s.RegisterService(&_Send_serviceDesc, srv) +} + +func _Send_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSend) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SendServer).Send(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/Send/Send", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SendServer).Send(ctx, req.(*MsgSend)) + } + return interceptor(ctx, in, info, handler) +} + +var _Send_serviceDesc = grpc.ServiceDesc{ + ServiceName: "Send", + HandlerType: (*SendServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Send", + Handler: _Send_Send_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "messages.proto", +} + +// NestedMessagesClient is the client API for NestedMessages service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type NestedMessagesClient interface { + Check(ctx context.Context, in *MsgNestedMessages, opts ...grpc.CallOption) (*MsgCreateNestedMessagesResponse, error) +} + +type nestedMessagesClient struct { + cc grpc1.ClientConn +} + +func NewNestedMessagesClient(cc grpc1.ClientConn) NestedMessagesClient { + return &nestedMessagesClient{cc} +} + +func (c *nestedMessagesClient) Check(ctx context.Context, in *MsgNestedMessages, opts ...grpc.CallOption) (*MsgCreateNestedMessagesResponse, error) { + out := new(MsgCreateNestedMessagesResponse) + err := c.cc.Invoke(ctx, "/NestedMessages/Check", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// NestedMessagesServer is the server API for NestedMessages service. +type NestedMessagesServer interface { + Check(context.Context, *MsgNestedMessages) (*MsgCreateNestedMessagesResponse, error) +} + +// UnimplementedNestedMessagesServer can be embedded to have forward compatible implementations. +type UnimplementedNestedMessagesServer struct { +} + +func (*UnimplementedNestedMessagesServer) Check(ctx context.Context, req *MsgNestedMessages) (*MsgCreateNestedMessagesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Check not implemented") +} + +func RegisterNestedMessagesServer(s grpc1.Server, srv NestedMessagesServer) { + s.RegisterService(&_NestedMessages_serviceDesc, srv) +} + +func _NestedMessages_Check_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgNestedMessages) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NestedMessagesServer).Check(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/NestedMessages/Check", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NestedMessagesServer).Check(ctx, req.(*MsgNestedMessages)) + } + return interceptor(ctx, in, info, handler) +} + +var _NestedMessages_serviceDesc = grpc.ServiceDesc{ + ServiceName: "NestedMessages", + HandlerType: (*NestedMessagesServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Check", + Handler: _NestedMessages_Check_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "messages.proto", +} + func (m *MsgCounter) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -725,39 +1066,173 @@ func (m *MsgCreateKeyValueResponse) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } -func encodeVarintMessages(dAtA []byte, offset int, v uint64) int { - offset -= sovMessages(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *MsgSend) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *MsgCounter) Size() (n int) { - if m == nil { - return 0 - } + +func (m *MsgSend) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSend) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.Counter != 0 { - n += 1 + sovMessages(uint64(m.Counter)) + if len(m.Amount) > 0 { + i -= len(m.Amount) + copy(dAtA[i:], m.Amount) + i = encodeVarintMessages(dAtA, i, uint64(len(m.Amount))) + i-- + dAtA[i] = 0x1a } - if m.FailOnHandler { - n += 2 + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintMessages(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x12 } - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovMessages(uint64(l)) + if len(m.From) > 0 { + i -= len(m.From) + copy(dAtA[i:], m.From) + i = encodeVarintMessages(dAtA, i, uint64(len(m.From))) + i-- + dAtA[i] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *MsgCounter2) Size() (n int) { - if m == nil { - return 0 +func (m *MsgSendResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSendResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSendResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgNestedMessages) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgNestedMessages) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgNestedMessages) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = 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] = 0x12 + } + if len(m.Messages) > 0 { + for iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Messages[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMessages(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *MsgCreateNestedMessagesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgCreateNestedMessagesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreateNestedMessagesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintMessages(dAtA []byte, offset int, v uint64) int { + offset -= sovMessages(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgCounter) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Counter != 0 { + n += 1 + sovMessages(uint64(m.Counter)) + } + if m.FailOnHandler { + n += 2 + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovMessages(uint64(l)) + } + return n +} + +func (m *MsgCounter2) Size() (n int) { + if m == nil { + return 0 } var l int _ = l @@ -813,6 +1288,64 @@ func (m *MsgCreateKeyValueResponse) Size() (n int) { return n } +func (m *MsgSend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.From) + if l > 0 { + n += 1 + l + sovMessages(uint64(l)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovMessages(uint64(l)) + } + l = len(m.Amount) + if l > 0 { + n += 1 + l + sovMessages(uint64(l)) + } + return n +} + +func (m *MsgSendResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgNestedMessages) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Messages) > 0 { + for _, e := range m.Messages { + l = e.Size() + n += 1 + l + sovMessages(uint64(l)) + } + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovMessages(uint64(l)) + } + return n +} + +func (m *MsgCreateNestedMessagesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func sovMessages(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1311,6 +1844,368 @@ func (m *MsgCreateKeyValueResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgSend) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSend: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSend: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field From", 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.From = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", 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.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", 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.Amount = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMessages(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSendResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSendResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSendResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipMessages(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgNestedMessages) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgNestedMessages: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgNestedMessages: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Messages", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMessages + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMessages + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Messages = append(m.Messages, &any.Any{}) + if err := m.Messages[len(m.Messages)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + 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:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgCreateNestedMessagesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgCreateNestedMessagesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCreateNestedMessagesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipMessages(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipMessages(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/baseapp/testutil/messages.proto b/baseapp/testutil/messages.proto index d2b25d24c117..d730cad03c04 100644 --- a/baseapp/testutil/messages.proto +++ b/baseapp/testutil/messages.proto @@ -34,6 +34,25 @@ message MsgKeyValue { message MsgCreateKeyValueResponse {} +message MsgSend { + option (cosmos.msg.v1.signer) = "from"; + + string from = 1; + string to = 2; + string amount = 3; +} + +message MsgSendResponse {} + +message MsgNestedMessages { + option (cosmos.msg.v1.signer) = "signer"; + + repeated google.protobuf.Any messages = 1; + string signer = 2; +} + +message MsgCreateNestedMessagesResponse {} + service Counter { rpc IncrementCounter(MsgCounter) returns (MsgCreateCounterResponse); } @@ -44,4 +63,12 @@ service Counter2 { service KeyValue { rpc Set(MsgKeyValue) returns (MsgCreateKeyValueResponse); -} \ No newline at end of file +} + +service Send { + rpc Send(MsgSend) returns (MsgSendResponse); +} + +service NestedMessages { + rpc Check(MsgNestedMessages) returns (MsgCreateNestedMessagesResponse); +} diff --git a/baseapp/utils_test.go b/baseapp/utils_test.go index 8369a42975c7..a127018c15a5 100644 --- a/baseapp/utils_test.go +++ b/baseapp/utils_test.go @@ -7,6 +7,7 @@ import ( "encoding/json" "errors" "fmt" + codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" "net/url" "reflect" "strconv" @@ -375,3 +376,58 @@ func wonkyMsg(t *testing.T, cfg client.TxConfig, tx signing.Tx) signing.Tx { require.NoError(t, err) return builder.GetTx() } + +type SendServerImpl struct{} + +func (s SendServerImpl) Send(ctx context.Context, send *baseapptestutil.MsgSend) (*baseapptestutil.MsgSendResponse, error) { + + if send.From == "" { + return nil, errors.New("from address cannot be empty") + } + if send.To == "" { + return nil, errors.New("to address cannot be empty") + } + + _, err := sdk.ParseCoinNormalized(send.Amount) + if err != nil { + return nil, err + } + + return &baseapptestutil.MsgSendResponse{}, nil +} + +type NesteMessgesServerImpl struct { +} + +func (n NesteMessgesServerImpl) Check(ctx context.Context, message *baseapptestutil.MsgNestedMessages) (*baseapptestutil.MsgCreateNestedMessagesResponse, error) { + cdc := codectestutil.CodecOptions{}.NewCodec() + baseapptestutil.RegisterInterfaces(cdc.InterfaceRegistry()) + + signer, _, err := cdc.GetMsgV1Signers(message) + if err != nil { + return nil, err + } + if len(signer) != 1 { + return nil, fmt.Errorf("expected 1 signer, got %d", len(signer)) + } + + msgs, err := message.GetMsgs() + if err != nil { + return nil, err + } + + for _, msg := range msgs { + s, _, err := cdc.GetMsgV1Signers(msg) + if err != nil { + return nil, err + } + if len(s) != 1 { + return nil, fmt.Errorf("expected 1 signer, got %d", len(s)) + } + if !bytes.Equal(signer[0], s[0]) { + return nil, errors.New("signer does not match") + } + + } + return nil, nil +} From cc1efda68cb8e24b514b06e39a791f8d82785f9c Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Mon, 6 May 2024 14:59:00 +0200 Subject: [PATCH 02/14] lint --- baseapp/abci_test.go | 2 +- baseapp/testutil/messages.go | 1 + baseapp/testutil/messages.proto | 6 +++--- baseapp/utils_test.go | 6 ++---- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 47ff4a024f78..34a2439a0402 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -34,6 +34,7 @@ import ( snapshottypes "cosmossdk.io/store/snapshots/types" storetypes "cosmossdk.io/store/types" "cosmossdk.io/x/auth/signing" + "github.com/cosmos/cosmos-sdk/baseapp" baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil" "github.com/cosmos/cosmos-sdk/baseapp/testutil/mock" @@ -871,7 +872,6 @@ func TestABCI_Query_SimulateNestedMessagesTx(t *testing.T) { require.NoError(t, err) require.NotNil(t, result) } - }) } } diff --git a/baseapp/testutil/messages.go b/baseapp/testutil/messages.go index bffce60ba976..1bc8a8bd920f 100644 --- a/baseapp/testutil/messages.go +++ b/baseapp/testutil/messages.go @@ -2,6 +2,7 @@ package testutil import ( errorsmod "cosmossdk.io/errors" + codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/codec" diff --git a/baseapp/testutil/messages.proto b/baseapp/testutil/messages.proto index d730cad03c04..2e0cfd15195f 100644 --- a/baseapp/testutil/messages.proto +++ b/baseapp/testutil/messages.proto @@ -37,8 +37,8 @@ message MsgCreateKeyValueResponse {} message MsgSend { option (cosmos.msg.v1.signer) = "from"; - string from = 1; - string to = 2; + string from = 1; + string to = 2; string amount = 3; } @@ -48,7 +48,7 @@ message MsgNestedMessages { option (cosmos.msg.v1.signer) = "signer"; repeated google.protobuf.Any messages = 1; - string signer = 2; + string signer = 2; } message MsgCreateNestedMessagesResponse {} diff --git a/baseapp/utils_test.go b/baseapp/utils_test.go index a127018c15a5..648146a53f50 100644 --- a/baseapp/utils_test.go +++ b/baseapp/utils_test.go @@ -7,7 +7,6 @@ import ( "encoding/json" "errors" "fmt" - codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" "net/url" "reflect" "strconv" @@ -33,6 +32,7 @@ import ( baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil" "github.com/cosmos/cosmos-sdk/client" addresscodec "github.com/cosmos/cosmos-sdk/codec/address" + codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" @@ -380,7 +380,6 @@ func wonkyMsg(t *testing.T, cfg client.TxConfig, tx signing.Tx) signing.Tx { type SendServerImpl struct{} func (s SendServerImpl) Send(ctx context.Context, send *baseapptestutil.MsgSend) (*baseapptestutil.MsgSendResponse, error) { - if send.From == "" { return nil, errors.New("from address cannot be empty") } @@ -396,8 +395,7 @@ func (s SendServerImpl) Send(ctx context.Context, send *baseapptestutil.MsgSend) return &baseapptestutil.MsgSendResponse{}, nil } -type NesteMessgesServerImpl struct { -} +type NesteMessgesServerImpl struct{} func (n NesteMessgesServerImpl) Check(ctx context.Context, message *baseapptestutil.MsgNestedMessages) (*baseapptestutil.MsgCreateNestedMessagesResponse, error) { cdc := codectestutil.CodecOptions{}.NewCodec() From 9556fe5b8205186d8aaaf0584a542c2bf2ec8f43 Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Mon, 6 May 2024 15:59:18 +0200 Subject: [PATCH 03/14] CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00b22e6b3e42..db72cbc26e09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ Every module contains its own CHANGELOG.md. Please refer to the module you are interested in. ### Features + +* (baseapp) [#20291](https://github.com/cosmos/cosmos-sdk/pull/20291) Simualte nested messages. * (tests) [#20013](https://github.com/cosmos/cosmos-sdk/pull/20013) Introduce system tests to run multi node local testnet in CI * (runtime) [#19953](https://github.com/cosmos/cosmos-sdk/pull/19953) Implement `core/transaction.Service` in runtime. * (client) [#19905](https://github.com/cosmos/cosmos-sdk/pull/19905) Add grpc client config to `client.toml`. From 940916779d37183e2f43cacc0086426b1964cb93 Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Mon, 6 May 2024 18:13:19 +0200 Subject: [PATCH 04/14] fix: typo --- baseapp/abci_test.go | 2 +- baseapp/utils_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 34a2439a0402..9c0a6714a18a 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -774,7 +774,7 @@ func TestABCI_Query_SimulateNestedMessagesTx(t *testing.T) { }) require.NoError(t, err) - baseapptestutil.RegisterNestedMessagesServer(suite.baseApp.MsgServiceRouter(), NesteMessgesServerImpl{}) + baseapptestutil.RegisterNestedMessagesServer(suite.baseApp.MsgServiceRouter(), NestedMessgesServerImpl{}) baseapptestutil.RegisterSendServer(suite.baseApp.MsgServiceRouter(), SendServerImpl{}) _, _, addr := testdata.KeyTestPubAddr() diff --git a/baseapp/utils_test.go b/baseapp/utils_test.go index 648146a53f50..a16f4b63fb78 100644 --- a/baseapp/utils_test.go +++ b/baseapp/utils_test.go @@ -395,9 +395,9 @@ func (s SendServerImpl) Send(ctx context.Context, send *baseapptestutil.MsgSend) return &baseapptestutil.MsgSendResponse{}, nil } -type NesteMessgesServerImpl struct{} +type NestedMessgesServerImpl struct{} -func (n NesteMessgesServerImpl) Check(ctx context.Context, message *baseapptestutil.MsgNestedMessages) (*baseapptestutil.MsgCreateNestedMessagesResponse, error) { +func (n NestedMessgesServerImpl) Check(_ context.Context, message *baseapptestutil.MsgNestedMessages) (*baseapptestutil.MsgCreateNestedMessagesResponse, error) { cdc := codectestutil.CodecOptions{}.NewCodec() baseapptestutil.RegisterInterfaces(cdc.InterfaceRegistry()) From 267b4b4b48d23b5b8fc1c0b3c0a043206e0ad375 Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Tue, 7 May 2024 10:07:50 +0200 Subject: [PATCH 05/14] typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db72cbc26e09..71b9c416caa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i ### Features -* (baseapp) [#20291](https://github.com/cosmos/cosmos-sdk/pull/20291) Simualte nested messages. +* (baseapp) [#20291](https://github.com/cosmos/cosmos-sdk/pull/20291) Simulate nested messages. * (tests) [#20013](https://github.com/cosmos/cosmos-sdk/pull/20013) Introduce system tests to run multi node local testnet in CI * (runtime) [#19953](https://github.com/cosmos/cosmos-sdk/pull/19953) Implement `core/transaction.Service` in runtime. * (client) [#19905](https://github.com/cosmos/cosmos-sdk/pull/19905) Add grpc client config to `client.toml`. From acfa637baefe6c4ca4547453e9ae82fe066a9394 Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Tue, 7 May 2024 10:18:28 +0200 Subject: [PATCH 06/14] fix: InitChainRequest --- baseapp/abci_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 54447a6095a3..73bb03a04292 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -23,7 +23,7 @@ import ( protoio "github.com/cosmos/gogoproto/io" "github.com/cosmos/gogoproto/jsonpb" "github.com/cosmos/gogoproto/proto" - gogotypes "github.com/cosmos/gogoproto/types" + gogotypes "github.com/cosmos/gogoproto/types" any "github.com/cosmos/gogoproto/types/any" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" @@ -770,7 +770,7 @@ func TestABCI_Query_SimulateNestedMessagesTx(t *testing.T) { } suite := NewBaseAppSuite(t, anteOpt) - _, err := suite.baseApp.InitChain(&abci.RequestInitChain{ + _, err := suite.baseApp.InitChain(&abci.InitChainRequest{ ConsensusParams: &cmtproto.ConsensusParams{}, }) require.NoError(t, err) From e9569ed6764ece10f79763130cc42833ec00d479 Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Thu, 9 May 2024 12:29:10 +0200 Subject: [PATCH 07/14] update: use protoadapt instead of unpack --- baseapp/baseapp.go | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 0a8af93c615e..a98fe4ca2faf 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -13,11 +13,10 @@ import ( cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" "github.com/cometbft/cometbft/crypto/tmhash" dbm "github.com/cosmos/cosmos-db" - "github.com/cosmos/cosmos-proto/anyutil" "github.com/cosmos/gogoproto/proto" "golang.org/x/exp/maps" protov2 "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/protoadapt" "cosmossdk.io/core/header" errorsmod "cosmossdk.io/errors" @@ -1104,19 +1103,7 @@ func (app *BaseApp) simulateNestedMessages(ctx sdk.Context, msg HasNestedMsgs) e func (app *BaseApp) msgsV1ToMsgsV2(msgs []sdk.Msg) ([]protov2.Message, error) { msgsV2 := make([]protov2.Message, len(msgs)) for i, msg := range msgs { - gogoAny, err := codectypes.NewAnyWithValue(msg) - if err != nil { - return nil, err - } - anyMsg := &anypb.Any{ - TypeUrl: gogoAny.TypeUrl, - Value: gogoAny.Value, - } - msgV2, err := anyutil.Unpack(anyMsg, app.cdc.InterfaceRegistry().SigningContext().FileResolver(), app.cdc.InterfaceRegistry().SigningContext().TypeResolver()) - if err != nil { - return nil, err - } - msgsV2[i] = msgV2 + msgsV2[i] = protoadapt.MessageV2Of(msg) } return msgsV2, nil From 6d0e987299c66226491609204a770ca558c607c9 Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Thu, 9 May 2024 16:44:03 +0200 Subject: [PATCH 08/14] update: check for nested messages in nested messages --- baseapp/abci_test.go | 123 +++++++++++++++++++++++++++++-------------- baseapp/baseapp.go | 37 ++++++++++--- 2 files changed, 112 insertions(+), 48 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 73bb03a04292..0f1de773cbda 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -14,6 +14,8 @@ import ( "testing" "time" + "github.com/cosmos/cosmos-sdk/codec" + abci "github.com/cometbft/cometbft/abci/types" cmtprotocrypto "github.com/cometbft/cometbft/api/cometbft/crypto/v1" cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" @@ -760,6 +762,16 @@ func TestABCI_FinalizeBlock_MultiMsg(t *testing.T) { require.Equal(t, int64(2), msgCounter2) } +func anyMessage(t *testing.T, cdc codec.Codec, msg *baseapptestutil.MsgSend) *any.Any { + t.Helper() + b, err := cdc.Marshal(msg) + require.NoError(t, err) + return &any.Any{ + TypeUrl: sdk.MsgTypeURL(msg), + Value: b, + } +} + func TestABCI_Query_SimulateNestedMessagesTx(t *testing.T) { gasConsumed := uint64(5) anteOpt := func(bapp *baseapp.BaseApp) { @@ -781,60 +793,92 @@ func TestABCI_Query_SimulateNestedMessagesTx(t *testing.T) { _, _, addr := testdata.KeyTestPubAddr() _, _, toAddr := testdata.KeyTestPubAddr() tests := []struct { - name string - nestedMsgs []*baseapptestutil.MsgSend - wantErr bool + name string + message sdk.Msg + wantErr bool }{ { name: "ok nested message", - nestedMsgs: []*baseapptestutil.MsgSend{ - { - From: addr.String(), - To: toAddr.String(), - Amount: "10000stake", - }, + message: &baseapptestutil.MsgSend{ + From: addr.String(), + To: toAddr.String(), + Amount: "10000stake", }, }, { name: "different signers", - nestedMsgs: []*baseapptestutil.MsgSend{ - { - From: toAddr.String(), - To: addr.String(), - Amount: "10000stake", - }, + message: &baseapptestutil.MsgSend{ + From: toAddr.String(), + To: addr.String(), + Amount: "10000stake", }, wantErr: true, }, { name: "empty from", - nestedMsgs: []*baseapptestutil.MsgSend{ - { - From: "", - To: toAddr.String(), - Amount: "10000stake", - }, + message: &baseapptestutil.MsgSend{ + From: "", + To: toAddr.String(), + Amount: "10000stake", }, wantErr: true, }, { name: "empty to", - nestedMsgs: []*baseapptestutil.MsgSend{ - { - From: addr.String(), - To: "", - Amount: "10000stake", - }, + message: &baseapptestutil.MsgSend{ + From: addr.String(), + To: "", + Amount: "10000stake", }, wantErr: true, }, { name: "negative amount", - nestedMsgs: []*baseapptestutil.MsgSend{ - { - From: addr.String(), - To: toAddr.String(), - Amount: "-10000stake", + message: &baseapptestutil.MsgSend{ + From: addr.String(), + To: toAddr.String(), + Amount: "-10000stake", + }, + wantErr: true, + }, + { + name: "with nested messages", + message: &baseapptestutil.MsgNestedMessages{ + Signer: addr.String(), + Messages: []*any.Any{ + anyMessage(t, suite.cdc, &baseapptestutil.MsgSend{ + From: addr.String(), + To: toAddr.String(), + Amount: "10000stake", + }), + }, + }, + wantErr: false, + }, + { + name: "with invalid nested messages", + message: &baseapptestutil.MsgNestedMessages{ + Signer: addr.String(), + Messages: []*any.Any{ + anyMessage(t, suite.cdc, &baseapptestutil.MsgSend{ + From: "", + To: toAddr.String(), + Amount: "10000stake", + }), + }, + }, + wantErr: true, + }, + { + name: "with different signer ", + message: &baseapptestutil.MsgNestedMessages{ + Signer: addr.String(), + Messages: []*any.Any{ + anyMessage(t, suite.cdc, &baseapptestutil.MsgSend{ + From: toAddr.String(), + To: addr.String(), + Amount: "10000stake", + }), }, }, wantErr: true, @@ -842,15 +886,14 @@ func TestABCI_Query_SimulateNestedMessagesTx(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - nestedMessages := make([]*any.Any, len(tt.nestedMsgs)) - for i, msg := range tt.nestedMsgs { - b, err := suite.cdc.Marshal(msg) - require.NoError(t, err) - nestedMessages[i] = &any.Any{ - TypeUrl: sdk.MsgTypeURL(msg), - Value: b, - } + nestedMessages := make([]*any.Any, 1) + b, err := suite.cdc.Marshal(tt.message) + require.NoError(t, err) + nestedMessages[0] = &any.Any{ + TypeUrl: sdk.MsgTypeURL(tt.message), + Value: b, } + msg := &baseapptestutil.MsgNestedMessages{ Messages: nestedMessages, Signer: addr.String(), diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index a98fe4ca2faf..91e4a97da5e7 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -13,10 +13,11 @@ import ( cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" "github.com/cometbft/cometbft/crypto/tmhash" dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-proto/anyutil" "github.com/cosmos/gogoproto/proto" "golang.org/x/exp/maps" protov2 "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/protoadapt" + "google.golang.org/protobuf/types/known/anypb" "cosmossdk.io/core/header" errorsmod "cosmossdk.io/errors" @@ -962,10 +963,6 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res if mode == execModeSimulate { nestedMsgsContext, _ := app.cacheTxContext(ctx, txBytes) for _, msg := range msgs { - msg, ok := msg.(HasNestedMsgs) - if !ok { - continue - } nestedErr := app.simulateNestedMessages(nestedMsgsContext, msg) if nestedErr != nil { return gInfo, nil, anteEvents, nestedErr @@ -1080,12 +1077,24 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, msgsV2 []protov2.Me } // simulateNestedMessages simulates a message nested messages. -func (app *BaseApp) simulateNestedMessages(ctx sdk.Context, msg HasNestedMsgs) error { - msgs, err := msg.GetMsgs() +func (app *BaseApp) simulateNestedMessages(ctx sdk.Context, msg sdk.Msg) error { + nestedMsgs, ok := msg.(HasNestedMsgs) + if !ok { + return nil + } + + msgs, err := nestedMsgs.GetMsgs() if err != nil { return err } + for _, msg := range msgs { + err = app.simulateNestedMessages(ctx, msg) + if err != nil { + return err + } + } + if err := validateBasicTxMsgs(app.msgServiceRouter, msgs); err != nil { return err } @@ -1103,7 +1112,19 @@ func (app *BaseApp) simulateNestedMessages(ctx sdk.Context, msg HasNestedMsgs) e func (app *BaseApp) msgsV1ToMsgsV2(msgs []sdk.Msg) ([]protov2.Message, error) { msgsV2 := make([]protov2.Message, len(msgs)) for i, msg := range msgs { - msgsV2[i] = protoadapt.MessageV2Of(msg) + gogoAny, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return nil, err + } + anyMsg := &anypb.Any{ + TypeUrl: gogoAny.TypeUrl, + Value: gogoAny.Value, + } + msgV2, err := anyutil.Unpack(anyMsg, app.cdc.InterfaceRegistry().SigningContext().FileResolver(), app.cdc.InterfaceRegistry().SigningContext().TypeResolver()) + if err != nil { + return nil, err + } + msgsV2[i] = msgV2 } return msgsV2, nil From f1544b226b486bf3eb43f3b571080ff9459dd19d Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Mon, 24 Jun 2024 11:31:55 +0200 Subject: [PATCH 09/14] fix: use protoreflect --- baseapp/abci_test.go | 1 - baseapp/baseapp.go | 14 +++++++++----- baseapp/utils_test.go | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index bd280f0c98bb..7c9074180109 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -16,7 +16,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" - abci "github.com/cometbft/cometbft/abci/types" abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" cmtprotocrypto "github.com/cometbft/cometbft/api/cometbft/crypto/v1" cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 06e558a2104d..feff33e980f6 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -17,8 +17,8 @@ import ( "github.com/cosmos/gogoproto/proto" "golang.org/x/exp/maps" protov2 "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/known/anypb" "cosmossdk.io/core/header" "cosmossdk.io/core/log" @@ -1101,12 +1101,16 @@ func (app *BaseApp) simulateNestedMessages(ctx sdk.Context, msg sdk.Msg) error { return err } - msgsV2, err := app.msgsV1ToMsgsV2(msgs) - if err != nil { - return err + protoMessages := make([]protoreflect.Message, len(msgs)) + for i, msg := range msgs { + _, protoMsg, err := app.cdc.GetMsgSigners(msg) + if err != nil { + return err + } + protoMessages[i] = protoMsg } - _, err = app.runMsgs(ctx, msgs, msgsV2, execModeSimulate) + _, err = app.runMsgs(ctx, msgs, protoMessages, execModeSimulate) return err } diff --git a/baseapp/utils_test.go b/baseapp/utils_test.go index ded4f0d8d272..6cb86ceee2c5 100644 --- a/baseapp/utils_test.go +++ b/baseapp/utils_test.go @@ -401,7 +401,7 @@ func (n NestedMessgesServerImpl) Check(_ context.Context, message *baseapptestut cdc := codectestutil.CodecOptions{}.NewCodec() baseapptestutil.RegisterInterfaces(cdc.InterfaceRegistry()) - signer, _, err := cdc.GetMsgV1Signers(message) + signer, _, err := cdc.GetMsgSigners(message) if err != nil { return nil, err } @@ -415,7 +415,7 @@ func (n NestedMessgesServerImpl) Check(_ context.Context, message *baseapptestut } for _, msg := range msgs { - s, _, err := cdc.GetMsgV1Signers(msg) + s, _, err := cdc.GetMsgSigners(msg) if err != nil { return nil, err } From 60516193c4b3f80fabc025c4c4dee882ac0177cc Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Tue, 25 Jun 2024 11:15:58 +0200 Subject: [PATCH 10/14] update: check if gas should be added --- baseapp/abci_test.go | 82 ++++++++++++++++++++++++++++++++++++++++-- baseapp/baseapp.go | 14 ++++++-- baseapp/options.go | 13 +++++++ baseapp/utils_test.go | 24 ++++++++++--- simapp/app.go | 3 +- simapp/app_di.go | 4 +-- x/gov/keeper/config.go | 4 +++ 7 files changed, 131 insertions(+), 13 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 7c9074180109..6627917a4fbb 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -774,10 +774,9 @@ func anyMessage(t *testing.T, cdc codec.Codec, msg *baseapptestutil.MsgSend) *an } func TestABCI_Query_SimulateNestedMessagesTx(t *testing.T) { - gasConsumed := uint64(5) anteOpt := func(bapp *baseapp.BaseApp) { bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { - newCtx = ctx.WithGasMeter(storetypes.NewGasMeter(gasConsumed)) + newCtx = ctx.WithGasMeter(storetypes.NewGasMeter(uint64(15))) return }) } @@ -854,7 +853,6 @@ func TestABCI_Query_SimulateNestedMessagesTx(t *testing.T) { }), }, }, - wantErr: false, }, { name: "with invalid nested messages", @@ -921,6 +919,84 @@ func TestABCI_Query_SimulateNestedMessagesTx(t *testing.T) { } } +func TestABCI_Query_SimulateNestedMessagesGas(t *testing.T) { + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + newCtx = ctx.WithGasMeter(storetypes.NewGasMeter(uint64(10))) + return + }) + } + + _, _, addr := testdata.KeyTestPubAddr() + _, _, toAddr := testdata.KeyTestPubAddr() + + tests := []struct { + name string + suite *BaseAppSuite + message sdk.Msg + consumedGas uint64 + }{ + { + name: "add gas", + suite: NewBaseAppSuite(t, anteOpt), + message: &baseapptestutil.MsgSend{ + From: addr.String(), + To: toAddr.String(), + Amount: "10000stake", + }, + consumedGas: 10, + }, + { + name: "don't add gas", + suite: NewBaseAppSuite(t, anteOpt, baseapp.SetExcludeNestedMsgsGas([]sdk.Msg{&baseapptestutil.MsgNestedMessages{}})), + message: &baseapptestutil.MsgSend{ + From: addr.String(), + To: toAddr.String(), + Amount: "10000stake", + }, + consumedGas: 5, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := tt.suite.baseApp.InitChain(&abci.InitChainRequest{ + ConsensusParams: &cmtproto.ConsensusParams{}, + }) + require.NoError(t, err) + + baseapptestutil.RegisterNestedMessagesServer(tt.suite.baseApp.MsgServiceRouter(), NestedMessgesServerImpl{}) + baseapptestutil.RegisterSendServer(tt.suite.baseApp.MsgServiceRouter(), SendServerImpl{}) + + nestedMessages := make([]*any.Any, 1) + b, err := tt.suite.cdc.Marshal(tt.message) + require.NoError(t, err) + nestedMessages[0] = &any.Any{ + TypeUrl: sdk.MsgTypeURL(tt.message), + Value: b, + } + + msg := &baseapptestutil.MsgNestedMessages{ + Messages: nestedMessages, + Signer: addr.String(), + } + + builder := tt.suite.txConfig.NewTxBuilder() + err = builder.SetMsgs(msg) + require.NoError(t, err) + setTxSignature(t, builder, 0) + tx := builder.GetTx() + + txBytes, err := tt.suite.txConfig.TxEncoder()(tx) + require.Nil(t, err) + + gas, result, err := tt.suite.baseApp.Simulate(txBytes) + require.NoError(t, err) + require.NotNil(t, result) + require.True(t, gas.GasUsed == tt.consumedGas) + }) + } +} + func TestABCI_Query_SimulateTx(t *testing.T) { gasConsumed := uint64(5) anteOpt := func(bapp *baseapp.BaseApp) { diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index feff33e980f6..50064d06a894 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -189,6 +189,9 @@ type BaseApp struct { // including the goroutine handling.This is experimental and must be enabled // by developers. optimisticExec *oe.OptimisticExecution + + // excludeNestedMsgsGas holds a set of message types for which gas costs for its nested messages are not calculated. + excludeNestedMsgsGas map[string]struct{} } // NewBaseApp returns a reference to an initialized BaseApp. It accepts a @@ -236,7 +239,9 @@ func NewBaseApp( if app.interBlockCache != nil { app.cms.SetInterBlockCache(app.interBlockCache) } - + if app.excludeNestedMsgsGas == nil { + app.excludeNestedMsgsGas = make(map[string]struct{}) + } app.runTxRecoveryMiddleware = newDefaultRecoveryMiddleware() // Initialize with an empty interface registry to avoid nil pointer dereference. @@ -963,12 +968,15 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res } if mode == execModeSimulate { - nestedMsgsContext, _ := app.cacheTxContext(ctx, txBytes) + gas := ctx.GasMeter().GasConsumed() for _, msg := range msgs { - nestedErr := app.simulateNestedMessages(nestedMsgsContext, msg) + nestedErr := app.simulateNestedMessages(ctx, msg) if nestedErr != nil { return gInfo, nil, anteEvents, nestedErr } + if _, ok := app.excludeNestedMsgsGas[sdk.MsgTypeURL(msg)]; ok { + ctx.GasMeter().RefundGas(ctx.GasMeter().GasConsumed()-gas, "simulation of nested messages") + } } } diff --git a/baseapp/options.go b/baseapp/options.go index 372c2411cf82..79aa2792b477 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -119,6 +119,19 @@ func SetOptimisticExecution(opts ...func(*oe.OptimisticExecution)) func(*BaseApp } } +// SetExcludeNestedMsgsGas sets the message types for which gas costs for its nested messages are not calculated when simulating. +func SetExcludeNestedMsgsGas(msgs []sdk.Msg) func(*BaseApp) { + return func(app *BaseApp) { + app.excludeNestedMsgsGas = make(map[string]struct{}) + for _, msg := range msgs { + if _, ok := msg.(HasNestedMsgs); !ok { + continue + } + app.excludeNestedMsgsGas[sdk.MsgTypeURL(msg)] = struct{}{} + } + } +} + func (app *BaseApp) SetName(name string) { if app.sealed { panic("SetName() on sealed BaseApp") diff --git a/baseapp/utils_test.go b/baseapp/utils_test.go index 6cb86ceee2c5..27668ce590c5 100644 --- a/baseapp/utils_test.go +++ b/baseapp/utils_test.go @@ -377,9 +377,12 @@ func wonkyMsg(t *testing.T, cfg client.TxConfig, tx signing.Tx) signing.Tx { return builder.GetTx() } -type SendServerImpl struct{} +type SendServerImpl struct { + gas uint64 +} func (s SendServerImpl) Send(ctx context.Context, send *baseapptestutil.MsgSend) (*baseapptestutil.MsgSendResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) if send.From == "" { return nil, errors.New("from address cannot be empty") } @@ -391,13 +394,20 @@ func (s SendServerImpl) Send(ctx context.Context, send *baseapptestutil.MsgSend) if err != nil { return nil, err } - + gas := s.gas + if gas == 0 { + gas = 5 + } + sdkCtx.GasMeter().ConsumeGas(gas, "send test") return &baseapptestutil.MsgSendResponse{}, nil } -type NestedMessgesServerImpl struct{} +type NestedMessgesServerImpl struct { + gas uint64 +} -func (n NestedMessgesServerImpl) Check(_ context.Context, message *baseapptestutil.MsgNestedMessages) (*baseapptestutil.MsgCreateNestedMessagesResponse, error) { +func (n NestedMessgesServerImpl) Check(ctx context.Context, message *baseapptestutil.MsgNestedMessages) (*baseapptestutil.MsgCreateNestedMessagesResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) cdc := codectestutil.CodecOptions{}.NewCodec() baseapptestutil.RegisterInterfaces(cdc.InterfaceRegistry()) @@ -427,5 +437,11 @@ func (n NestedMessgesServerImpl) Check(_ context.Context, message *baseapptestut } } + + gas := n.gas + if gas == 0 { + gas = 5 + } + sdkCtx.GasMeter().ConsumeGas(gas, "nested messages test") return nil, nil } diff --git a/simapp/app.go b/simapp/app.go index c441659f18c1..1d4bdd47b6af 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -246,7 +246,8 @@ func NewSimApp( voteExtHandler := NewVoteExtensionHandler() voteExtHandler.SetHandlers(bApp) } - baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution()) + baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution(), + baseapp.SetExcludeNestedMsgsGas(govkeeper.DefaultConfig().ExcludedNestedMsgsForGasSim)) bApp := baseapp.NewBaseApp(appName, logger, db, txConfig.TxDecoder(), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) diff --git a/simapp/app_di.go b/simapp/app_di.go index d2b27c7eefdc..78ed2944183c 100644 --- a/simapp/app_di.go +++ b/simapp/app_di.go @@ -137,7 +137,6 @@ func NewSimApp( appOpts, // supply the logger logger, - // ADVANCED CONFIGURATION // @@ -239,7 +238,8 @@ func NewSimApp( voteExtHandler := NewVoteExtensionHandler() voteExtHandler.SetHandlers(bApp) } - baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution()) + baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution(), + baseapp.SetExcludeNestedMsgsGas(govkeeper.DefaultConfig().ExcludedNestedMsgsForGasSim)) app.App = appBuilder.Build(db, traceStore, baseAppOptions...) diff --git a/x/gov/keeper/config.go b/x/gov/keeper/config.go index ea01891974a5..b066dce7396f 100644 --- a/x/gov/keeper/config.go +++ b/x/gov/keeper/config.go @@ -3,6 +3,7 @@ package keeper import ( "context" + "cosmossdk.io/core/transaction" "cosmossdk.io/math" v1 "cosmossdk.io/x/gov/types/v1" ) @@ -33,6 +34,8 @@ type Config struct { // CalculateVoteResultsAndVotingPowerFn is a function signature for calculating vote results and voting power // Keeping it nil will use the default implementation CalculateVoteResultsAndVotingPowerFn CalculateVoteResultsAndVotingPowerFn + // ExcludedNestedMsgsForGasSim is a list of messages that will avoid adding the gas of their nested messages when simulating + ExcludedNestedMsgsForGasSim []transaction.Msg } // DefaultConfig returns the default config for gov. @@ -43,5 +46,6 @@ func DefaultConfig() Config { MaxSummaryLen: 10200, MaxVoteOptionsLen: 0, // 0 means this param is disabled, hence all supported options are allowed CalculateVoteResultsAndVotingPowerFn: nil, + ExcludedNestedMsgsForGasSim: []transaction.Msg{&v1.MsgSubmitProposal{}}, } } From c035d34f310860549f41fc59e8d81eb89256be86 Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Tue, 25 Jun 2024 11:24:21 +0200 Subject: [PATCH 11/14] lint --- baseapp/abci_test.go | 3 +-- baseapp/baseapp.go | 25 ------------------------- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 6627917a4fbb..3d9197ebb3c1 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -14,8 +14,6 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/codec" - abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" cmtprotocrypto "github.com/cometbft/cometbft/api/cometbft/crypto/v1" cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" @@ -41,6 +39,7 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil" "github.com/cosmos/cosmos-sdk/baseapp/testutil/mock" + "github.com/cosmos/cosmos-sdk/codec" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/testutil" "github.com/cosmos/cosmos-sdk/testutil/testdata" diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 50064d06a894..9a3bb1666922 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -13,12 +13,9 @@ import ( cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" "github.com/cometbft/cometbft/crypto/tmhash" dbm "github.com/cosmos/cosmos-db" - "github.com/cosmos/cosmos-proto/anyutil" "github.com/cosmos/gogoproto/proto" "golang.org/x/exp/maps" - protov2 "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/types/known/anypb" "cosmossdk.io/core/header" "cosmossdk.io/core/log" @@ -1122,28 +1119,6 @@ func (app *BaseApp) simulateNestedMessages(ctx sdk.Context, msg sdk.Msg) error { return err } -// msgsV1ToMsgsV2 transforms v1 messages into v2. -func (app *BaseApp) msgsV1ToMsgsV2(msgs []sdk.Msg) ([]protov2.Message, error) { - msgsV2 := make([]protov2.Message, len(msgs)) - for i, msg := range msgs { - gogoAny, err := codectypes.NewAnyWithValue(msg) - if err != nil { - return nil, err - } - anyMsg := &anypb.Any{ - TypeUrl: gogoAny.TypeUrl, - Value: gogoAny.Value, - } - msgV2, err := anyutil.Unpack(anyMsg, app.cdc.InterfaceRegistry().SigningContext().FileResolver(), app.cdc.InterfaceRegistry().SigningContext().TypeResolver()) - if err != nil { - return nil, err - } - msgsV2[i] = msgV2 - } - - return msgsV2, nil -} - // makeABCIData generates the Data field to be sent to ABCI Check/DeliverTx. func makeABCIData(msgResponses []*codectypes.Any) ([]byte, error) { return proto.Marshal(&sdk.TxMsgData{MsgResponses: msgResponses}) From e5362a59cc026c2fab80dd336954cc9c68698ab4 Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Mon, 15 Jul 2024 12:40:14 +0200 Subject: [PATCH 12/14] update: gas is not added by default --- baseapp/abci_test.go | 10 +++++----- baseapp/baseapp.go | 27 +++++++++++++++------------ baseapp/options.go | 8 ++++---- simapp/app.go | 3 +-- simapp/app_di.go | 3 +-- x/gov/keeper/config.go | 4 ---- 6 files changed, 26 insertions(+), 29 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 3d9197ebb3c1..4fea776a8bf7 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -936,24 +936,24 @@ func TestABCI_Query_SimulateNestedMessagesGas(t *testing.T) { consumedGas uint64 }{ { - name: "add gas", + name: "don't add gas", suite: NewBaseAppSuite(t, anteOpt), message: &baseapptestutil.MsgSend{ From: addr.String(), To: toAddr.String(), Amount: "10000stake", }, - consumedGas: 10, + consumedGas: 5, }, { - name: "don't add gas", - suite: NewBaseAppSuite(t, anteOpt, baseapp.SetExcludeNestedMsgsGas([]sdk.Msg{&baseapptestutil.MsgNestedMessages{}})), + name: "add gas", + suite: NewBaseAppSuite(t, anteOpt, baseapp.SetIncludeNestedMsgsGas([]sdk.Msg{&baseapptestutil.MsgNestedMessages{}})), message: &baseapptestutil.MsgSend{ From: addr.String(), To: toAddr.String(), Amount: "10000stake", }, - consumedGas: 5, + consumedGas: 10, }, } for _, tt := range tests { diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index f00887b35b77..3599a35517ec 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -187,8 +187,8 @@ type BaseApp struct { // by developers. optimisticExec *oe.OptimisticExecution - // excludeNestedMsgsGas holds a set of message types for which gas costs for its nested messages are not calculated. - excludeNestedMsgsGas map[string]struct{} + // includeNestedMsgsGas holds a set of message types for which gas costs for its nested messages are calculated. + includeNestedMsgsGas map[string]struct{} } // NewBaseApp returns a reference to an initialized BaseApp. It accepts a @@ -236,8 +236,8 @@ func NewBaseApp( if app.interBlockCache != nil { app.cms.SetInterBlockCache(app.interBlockCache) } - if app.excludeNestedMsgsGas == nil { - app.excludeNestedMsgsGas = make(map[string]struct{}) + if app.includeNestedMsgsGas == nil { + app.includeNestedMsgsGas = make(map[string]struct{}) } app.runTxRecoveryMiddleware = newDefaultRecoveryMiddleware() @@ -965,15 +965,11 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res } if mode == execModeSimulate { - gas := ctx.GasMeter().GasConsumed() for _, msg := range msgs { nestedErr := app.simulateNestedMessages(ctx, msg) if nestedErr != nil { return gInfo, nil, anteEvents, nestedErr } - if _, ok := app.excludeNestedMsgsGas[sdk.MsgTypeURL(msg)]; ok { - ctx.GasMeter().RefundGas(ctx.GasMeter().GasConsumed()-gas, "simulation of nested messages") - } } } @@ -1095,6 +1091,10 @@ func (app *BaseApp) simulateNestedMessages(ctx sdk.Context, msg sdk.Msg) error { return err } + if err := validateBasicTxMsgs(app.msgServiceRouter, msgs); err != nil { + return err + } + for _, msg := range msgs { err = app.simulateNestedMessages(ctx, msg) if err != nil { @@ -1102,10 +1102,6 @@ func (app *BaseApp) simulateNestedMessages(ctx sdk.Context, msg sdk.Msg) error { } } - if err := validateBasicTxMsgs(app.msgServiceRouter, msgs); err != nil { - return err - } - protoMessages := make([]protoreflect.Message, len(msgs)) for i, msg := range msgs { _, protoMsg, err := app.cdc.GetMsgSigners(msg) @@ -1115,7 +1111,14 @@ func (app *BaseApp) simulateNestedMessages(ctx sdk.Context, msg sdk.Msg) error { protoMessages[i] = protoMsg } + initialGas := ctx.GasMeter().GasConsumed() _, err = app.runMsgs(ctx, msgs, protoMessages, execModeSimulate) + if err == nil { + if _, includeGas := app.includeNestedMsgsGas[sdk.MsgTypeURL(msg)]; !includeGas { + consumedGas := ctx.GasMeter().GasConsumed() - initialGas + ctx.GasMeter().RefundGas(consumedGas, "simulation of nested messages") + } + } return err } diff --git a/baseapp/options.go b/baseapp/options.go index 79aa2792b477..bcff418fb8b0 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -119,15 +119,15 @@ func SetOptimisticExecution(opts ...func(*oe.OptimisticExecution)) func(*BaseApp } } -// SetExcludeNestedMsgsGas sets the message types for which gas costs for its nested messages are not calculated when simulating. -func SetExcludeNestedMsgsGas(msgs []sdk.Msg) func(*BaseApp) { +// SetIncludeNestedMsgsGas sets the message types for which gas costs for its nested messages are calculated when simulating. +func SetIncludeNestedMsgsGas(msgs []sdk.Msg) func(*BaseApp) { return func(app *BaseApp) { - app.excludeNestedMsgsGas = make(map[string]struct{}) + app.includeNestedMsgsGas = make(map[string]struct{}) for _, msg := range msgs { if _, ok := msg.(HasNestedMsgs); !ok { continue } - app.excludeNestedMsgsGas[sdk.MsgTypeURL(msg)] = struct{}{} + app.includeNestedMsgsGas[sdk.MsgTypeURL(msg)] = struct{}{} } } } diff --git a/simapp/app.go b/simapp/app.go index 7a80caf2d000..d5a0269f8197 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -246,8 +246,7 @@ func NewSimApp( voteExtHandler := NewVoteExtensionHandler() voteExtHandler.SetHandlers(bApp) } - baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution(), - baseapp.SetExcludeNestedMsgsGas(govkeeper.DefaultConfig().ExcludedNestedMsgsForGasSim)) + baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution()) bApp := baseapp.NewBaseApp(appName, logger, db, txConfig.TxDecoder(), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) diff --git a/simapp/app_di.go b/simapp/app_di.go index fbe269ffab93..63beee09ab7e 100644 --- a/simapp/app_di.go +++ b/simapp/app_di.go @@ -240,8 +240,7 @@ func NewSimApp( voteExtHandler := NewVoteExtensionHandler() voteExtHandler.SetHandlers(bApp) } - baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution(), - baseapp.SetExcludeNestedMsgsGas(govkeeper.DefaultConfig().ExcludedNestedMsgsForGasSim)) + baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution()) app.App = appBuilder.Build(db, traceStore, baseAppOptions...) diff --git a/x/gov/keeper/config.go b/x/gov/keeper/config.go index b066dce7396f..ea01891974a5 100644 --- a/x/gov/keeper/config.go +++ b/x/gov/keeper/config.go @@ -3,7 +3,6 @@ package keeper import ( "context" - "cosmossdk.io/core/transaction" "cosmossdk.io/math" v1 "cosmossdk.io/x/gov/types/v1" ) @@ -34,8 +33,6 @@ type Config struct { // CalculateVoteResultsAndVotingPowerFn is a function signature for calculating vote results and voting power // Keeping it nil will use the default implementation CalculateVoteResultsAndVotingPowerFn CalculateVoteResultsAndVotingPowerFn - // ExcludedNestedMsgsForGasSim is a list of messages that will avoid adding the gas of their nested messages when simulating - ExcludedNestedMsgsForGasSim []transaction.Msg } // DefaultConfig returns the default config for gov. @@ -46,6 +43,5 @@ func DefaultConfig() Config { MaxSummaryLen: 10200, MaxVoteOptionsLen: 0, // 0 means this param is disabled, hence all supported options are allowed CalculateVoteResultsAndVotingPowerFn: nil, - ExcludedNestedMsgsForGasSim: []transaction.Msg{&v1.MsgSubmitProposal{}}, } } From 38854b6baf8c74e2a783faa0931d97e1462e1bc9 Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Fri, 26 Jul 2024 10:46:19 +0200 Subject: [PATCH 13/14] UPGRADING --- UPGRADING.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/UPGRADING.md b/UPGRADING.md index 887fb2a1e454..57ca7a65a82b 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -5,6 +5,39 @@ Note, always read the **SimApp** section for more information on application wir ## [Unreleased] +### BaseApp + +#### Nested Messages Simulation + +Now it is possible to simulate the nested messages of a message, providing developers with a powerful tool for +testing and predicting the behavior of complex transactions. This feature allows for a more comprehensive +evaluation of gas consumption, state changes, and potential errors that may occur when executing nested +messages. However, it's important to note that while the simulation can provide valuable insights, it does not +guarantee the correct execution of the nested messages in the future. Factors such as changes in the +blockchain state or updates to the protocol could potentially affect the actual execution of these nested +messages when the transaction is finally processed on the network. + +For example, consider a governance proposal that includes nested messages to update multiple protocol +parameters. At the time of simulation, the blockchain state may be suitable for executing all these nested +messages successfully. However, by the time the actual governance proposal is executed (which could be days or +weeks later), the blockchain state might have changed significantly. As a result, while the simulation showed +a successful execution, the actual governance proposal might fail when it's finally processed. + +By default, when simulating transactions, the gas cost of nested messages is not calculated. This means that +only the gas cost of the top-level message is considered. However, this behavior can be customized using the +`SetIncludeNestedMsgsGas` option when building the BaseApp. By providing a list of message types to this option, +you can specify which messages should have their nested message gas costs included in the simulation. This +allows for more accurate gas estimation for transactions involving specific message types that contain nested +messages, while maintaining the default behavior for other message types. + +Here is an example on how `SetIncludeNestedMsgsGas` option could be set to calculate the gas of a gov proposal +nested messages: +```go +baseAppOptions = append(baseAppOptions, baseapp.SetIncludeNestedMsgsGas([]sdk.Message{&gov.MsgSubmitProposal{}})) +// ... +app.App = appBuilder.Build(db, traceStore, baseAppOptions...) +``` + ### SimApp In this section we describe the changes made in Cosmos SDK' SimApp. From 99a166b9b9416988b6350bac30024e5d19a14ff2 Mon Sep 17 00:00:00 2001 From: Julian Toledano <jtoledanodiaz@gmail.com> Date: Fri, 26 Jul 2024 11:19:16 +0200 Subject: [PATCH 14/14] update: add SetIncludeNestedMsgsGas to app.go --- simapp/app.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/simapp/app.go b/simapp/app.go index d5a0269f8197..f276e5eaeb72 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -66,6 +66,7 @@ import ( "cosmossdk.io/x/gov" govkeeper "cosmossdk.io/x/gov/keeper" govtypes "cosmossdk.io/x/gov/types" + govv1 "cosmossdk.io/x/gov/types/v1" govv1beta1 "cosmossdk.io/x/gov/types/v1beta1" "cosmossdk.io/x/group" groupkeeper "cosmossdk.io/x/group/keeper" @@ -246,7 +247,8 @@ func NewSimApp( voteExtHandler := NewVoteExtensionHandler() voteExtHandler.SetHandlers(bApp) } - baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution()) + baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution(), + baseapp.SetIncludeNestedMsgsGas([]sdk.Msg{&govv1.MsgSubmitProposal{}})) bApp := baseapp.NewBaseApp(appName, logger, db, txConfig.TxDecoder(), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore)