diff --git a/CHANGELOG.md b/CHANGELOG.md index 660866500e77..30b7d373104c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -175,6 +175,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/staking) [#15701](https://github.com/cosmos/cosmos-sdk/pull/15701) `HistoricalInfoKey` now has a binary format. * (grpc-web) [#14652](https://github.com/cosmos/cosmos-sdk/pull/14652) Use same port for gRPC-Web and the API server. +* (abci) [#15845](https://github.com/cosmos/cosmos-sdk/pull/15845) Add `msg_index` to all event attributes to associate events and messages +* (abci) [#15845](https://github.com/cosmos/cosmos-sdk/pull/15845) Remove duplicating events in `logs` ### CLI Breaking Changes diff --git a/UPGRADING.md b/UPGRADING.md index f2fafaa33a11..c5970a152db0 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -36,6 +36,10 @@ simd config migrate v0.48 More information about [confix](https://docs.cosmos.network/main/tooling/confix). +#### Events + +The log section of abci.TxResult is not populated in the case of successful msg(s) execution. Instead a new attribute is added to all messages indicating the `msg_index` which identifies which events and attributes relate the same transaction + #### gRPC-Web gRPC-Web is now listening to the same address as the gRPC Gateway API server (default: `localhost:1317`). diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index cc762dad42c0..b53781d898f9 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -677,7 +677,7 @@ func TestABCI_DeliverTx(t *testing.T) { events := res.GetEvents() require.Len(t, events, 3, "should contain ante handler, message type and counter events respectively") require.Equal(t, sdk.MarkEventsToIndex(counterEvent("ante_handler", counter).ToABCIEvents(), map[string]struct{}{})[0], events[0], "ante handler event") - require.Equal(t, sdk.MarkEventsToIndex(counterEvent(sdk.EventTypeMessage, counter).ToABCIEvents(), map[string]struct{}{})[0], events[2], "msg handler update counter event") + require.Equal(t, sdk.MarkEventsToIndex(counterEvent(sdk.EventTypeMessage, counter).ToABCIEvents(), map[string]struct{}{})[0].Attributes[0], events[2].Attributes[0], "msg handler update counter event") } suite.baseApp.EndBlock(abci.RequestEndBlock{}) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index bf29ecc83f48..61833a674d7b 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -3,7 +3,7 @@ package baseapp import ( "fmt" "sort" - "strings" + "strconv" errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" @@ -773,7 +773,6 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re // 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 runTxMode) (*sdk.Result, error) { - msgLogs := make(sdk.ABCIMessageLogs, 0, len(msgs)) events := sdk.EmptyEvents() var msgResponses []*codectypes.Any @@ -797,10 +796,15 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s // create message events msgEvents := createEvents(msgResult.GetEvents(), msg) - // append message events, data and logs + // append message events and data // // Note: Each message result's data must be length-prefixed in order to // separate each result. + for j, event := range msgEvents { + // append message index to all events + msgEvents[j] = event.AppendAttributes(sdk.NewAttribute("msg_index", strconv.Itoa(i))) + } + events = events.AppendEvents(msgEvents) // Each individual sdk.Result that went through the MsgServiceRouter @@ -816,7 +820,6 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s msgResponses = append(msgResponses, msgResponse) } - msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint32(i), msgResult.Log, msgEvents)) } data, err := makeABCIData(msgResponses) @@ -826,7 +829,6 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s return &sdk.Result{ Data: data, - Log: strings.TrimSpace(msgLogs.String()), Events: events.ToABCIEvents(), MsgResponses: msgResponses, }, nil diff --git a/baseapp/streaming_test.go b/baseapp/streaming_test.go index ca63305fcbfa..7ac58833d2a6 100644 --- a/baseapp/streaming_test.go +++ b/baseapp/streaming_test.go @@ -99,7 +99,7 @@ func TestABCI_MultiListener_StateChanges(t *testing.T) { events := res.GetEvents() require.Len(t, events, 3, "should contain ante handler, message type and counter events respectively") require.Equal(t, sdk.MarkEventsToIndex(counterEvent("ante_handler", counter).ToABCIEvents(), map[string]struct{}{})[0], events[0], "ante handler event") - require.Equal(t, sdk.MarkEventsToIndex(counterEvent(sdk.EventTypeMessage, counter).ToABCIEvents(), map[string]struct{}{})[0], events[2], "msg handler update counter event") + require.Equal(t, sdk.MarkEventsToIndex(counterEvent(sdk.EventTypeMessage, counter).ToABCIEvents(), map[string]struct{}{})[0].Attributes[0], events[2].Attributes[0], "msg handler update counter event") } suite.baseApp.EndBlock(abci.RequestEndBlock{}) diff --git a/docs/docs/core/08-events.md b/docs/docs/core/08-events.md index beb7e06b9491..0f133966e374 100644 --- a/docs/docs/core/08-events.md +++ b/docs/docs/core/08-events.md @@ -29,6 +29,7 @@ An Event contains: * A `type` to categorize the Event at a high-level; for example, the Cosmos SDK uses the `"message"` type to filter Events by `Msg`s. * A list of `attributes` are key-value pairs that give more information about the categorized Event. For example, for the `"message"` type, we can filter Events by key-value pairs using `message.action={some_action}`, `message.module={some_module}` or `message.sender={some_sender}`. +* A `msg_index` to identify which messages relate to the same transaction :::tip To parse the attribute values as strings, make sure to add `'` (single quotes) around each attribute value. diff --git a/tests/e2e/auth/suite.go b/tests/e2e/auth/suite.go index 3887ee44291f..0c0f776cb447 100644 --- a/tests/e2e/auth/suite.go +++ b/tests/e2e/auth/suite.go @@ -7,11 +7,11 @@ import ( "strings" "testing" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "cosmossdk.io/depinject" "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -440,7 +440,9 @@ func (s *E2ETestSuite) TestCLIQueryTxCmdByHash() { var result sdk.TxResponse s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &result)) s.Require().NotNil(result.Height) - s.Require().Contains(result.RawLog, tc.rawLogContains) + if ok := s.deepContains(result.Events, tc.rawLogContains); !ok { + s.Require().Fail("raw log does not contain the expected value, expected value: %s", tc.rawLogContains) + } } }) } @@ -1961,3 +1963,14 @@ func (s *E2ETestSuite) getBalances(clientCtx client.Context, addr sdk.AccAddress startTokens := balRes.Balances.AmountOf(denom) return startTokens } + +func (s *E2ETestSuite) deepContains(events []abci.Event, value string) bool { + for _, e := range events { + for _, attr := range e.Attributes { + if strings.Contains(attr.Value, value) { + return true + } + } + } + return false +} diff --git a/tests/e2e/group/suite.go b/tests/e2e/group/suite.go index 7f3422b81f46..54bf6aa4f9b9 100644 --- a/tests/e2e/group/suite.go +++ b/tests/e2e/group/suite.go @@ -10,6 +10,7 @@ import ( // without this import amino json encoding will fail when resolving any types _ "cosmossdk.io/api/cosmos/group/v1" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -202,9 +203,9 @@ func (s *E2ETestSuite) TearDownSuite() { } func (s *E2ETestSuite) getProposalIDFromTxResponse(txResp sdk.TxResponse) string { - s.Require().Greater(len(txResp.Logs), 0) - s.Require().NotNil(txResp.Logs[0].Events) - events := txResp.Logs[0].Events + s.Require().Greater(len(txResp.Events), 0) + s.Require().NotNil(txResp.Events[0]) + events := txResp.Events createProposalEvent, _ := sdk.TypedEventToEvent(&group.EventSubmitProposal{}) for _, e := range events { diff --git a/tests/e2e/staking/suite.go b/tests/e2e/staking/suite.go index 1814545564b3..1ddf4594afdc 100644 --- a/tests/e2e/staking/suite.go +++ b/tests/e2e/staking/suite.go @@ -255,7 +255,7 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() { s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) var hadEvent bool - events := txResp.Logs[0].GetEvents() + events := txResp.Events for i := 0; i < len(events); i++ { if events[i].GetType() == "create_validator" { attributes := events[i].GetAttributes() diff --git a/tests/e2e/tx/service_test.go b/tests/e2e/tx/service_test.go index 3295032363d1..ab650e8ea7c6 100644 --- a/tests/e2e/tx/service_test.go +++ b/tests/e2e/tx/service_test.go @@ -289,12 +289,12 @@ func (s *E2ETestSuite) TestGetTxEvents_GRPC() { "with pagination", &tx.GetTxsEventRequest{ Query: bankMsgSendEventAction, - Page: 2, + Page: 1, Limit: 2, }, false, "", - 1, + 2, }, { "with multi events", @@ -317,13 +317,13 @@ func (s *E2ETestSuite) TestGetTxEvents_GRPC() { s.Require().NoError(err) s.Require().GreaterOrEqual(len(grpcRes.Txs), 1) s.Require().Equal("foobar", grpcRes.Txs[0].Body.Memo) - s.Require().Equal(len(grpcRes.Txs), tc.expLen) + s.Require().Equal(tc.expLen, len(grpcRes.Txs)) // Make sure fields are populated. // ref: https://github.com/cosmos/cosmos-sdk/issues/8680 // ref: https://github.com/cosmos/cosmos-sdk/issues/8681 s.Require().NotEmpty(grpcRes.TxResponses[0].Timestamp) - s.Require().NotEmpty(grpcRes.TxResponses[0].RawLog) + s.Require().Empty(grpcRes.TxResponses[0].RawLog) // logs are empty if the transactions are successful } }) } @@ -352,9 +352,9 @@ func (s *E2ETestSuite) TestGetTxEvents_GRPCGateway() { }, { "with pagination", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&page=%d&limit=%d", val.APIAddress, bankMsgSendEventAction, 2, 2), + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&page=%d&limit=%d", val.APIAddress, bankMsgSendEventAction, 1, 2), false, - "", 1, + "", 2, }, { "valid request: order by asc", @@ -474,7 +474,7 @@ func (s *E2ETestSuite) TestGetTx_GRPCGateway() { // ref: https://github.com/cosmos/cosmos-sdk/issues/8680 // ref: https://github.com/cosmos/cosmos-sdk/issues/8681 s.Require().NotEmpty(result.TxResponse.Timestamp) - s.Require().NotEmpty(result.TxResponse.RawLog) + s.Require().Empty(result.TxResponse.RawLog) // logs are empty on successful transactions } }) }