From 2b5f2598e82ac93a50f8c4c5447f74ef9106691e Mon Sep 17 00:00:00 2001 From: bruce-wayne2 Date: Fri, 22 Jul 2022 12:33:15 +0800 Subject: [PATCH 1/4] fix non-deterministic map iteration --- CHANGELOG.md | 1 + types/events.go | 15 ++++++++++++++- types/events_test.go | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9390a7f9e7d8..c055d67b5a6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -118,6 +118,7 @@ empty coins slice before it is used to create `banktype.MsgSend`. * (x/auth/tx) [#12474](https://github.com/cosmos/cosmos-sdk/pull/12474) Remove condition in GetTxsEvent that disallowed multiple equal signs, which would break event queries with base64 strings (i.e. query by signature). * [#12448](https://github.com/cosmos/cosmos-sdk/pull/12448) Start telemetry independently from the API server. * (store/rootmulti) [#12487](https://github.com/cosmos/cosmos-sdk/pull/12487) Fix non-deterministic map iteration. +* (types) [#UNSET](https://github.com/cosmos/cosmos-sdk/pull/UNSET) Fix non-deterministic map iteration. ## [v0.46.0-rc1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.46.0-rc1) - 2022-05-23 diff --git a/types/events.go b/types/events.go index dbff89ce2d02..322186f5e9c2 100644 --- a/types/events.go +++ b/types/events.go @@ -87,8 +87,12 @@ func TypedEventToEvent(tev proto.Message) (Event, error) { return Event{}, err } + // sort the keys to ensure the order is always the same + keys := orderedKeys(attrMap) + attrs := make([]abci.EventAttribute, 0, len(attrMap)) - for k, v := range attrMap { + for _, k := range keys { + v := attrMap[k] attrs = append(attrs, abci.EventAttribute{ Key: k, Value: string(v), @@ -101,6 +105,15 @@ func TypedEventToEvent(tev proto.Message) (Event, error) { }, nil } +func orderedKeys(m map[string]json.RawMessage) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + // ParseTypedEvent converts abci.Event back to typed event func ParseTypedEvent(event abci.Event) (proto.Message, error) { concreteGoType := proto.MessageType(event.Type) diff --git a/types/events_test.go b/types/events_test.go index a395f8c73838..a9aad208398c 100644 --- a/types/events_test.go +++ b/types/events_test.go @@ -67,6 +67,21 @@ func (s *eventsTestSuite) TestEventManager() { s.Require().Equal(em.Events(), events.AppendEvent(event)) } +func (s *eventsTestSuite) TestEmitTypedEvent() { + s.Run("deterministic key-value order", func() { + for i := 0; i < 10; i++ { + em := sdk.NewEventManager() + coin := sdk.NewCoin("fakedenom", sdk.NewInt(1999999)) + s.Require().NoError(em.EmitTypedEvent(&coin)) + s.Require().Len(em.Events(), 1) + attrs := em.Events()[0].Attributes + s.Require().Len(attrs, 2) + s.Require().Equal(attrs[0].Key, "amount") + s.Require().Equal(attrs[1].Key, "denom") + } + }) +} + func (s *eventsTestSuite) TestEventManagerTypedEvents() { em := sdk.NewEventManager() From fe7c36b2bfad0b9afea5955adadecfc1f160e918 Mon Sep 17 00:00:00 2001 From: bruce-wayne2 Date: Fri, 22 Jul 2022 12:36:09 +0800 Subject: [PATCH 2/4] update pull request id --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c055d67b5a6a..6cfe45a84b40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -118,7 +118,7 @@ empty coins slice before it is used to create `banktype.MsgSend`. * (x/auth/tx) [#12474](https://github.com/cosmos/cosmos-sdk/pull/12474) Remove condition in GetTxsEvent that disallowed multiple equal signs, which would break event queries with base64 strings (i.e. query by signature). * [#12448](https://github.com/cosmos/cosmos-sdk/pull/12448) Start telemetry independently from the API server. * (store/rootmulti) [#12487](https://github.com/cosmos/cosmos-sdk/pull/12487) Fix non-deterministic map iteration. -* (types) [#UNSET](https://github.com/cosmos/cosmos-sdk/pull/UNSET) Fix non-deterministic map iteration. +* (types) [#12693](https://github.com/cosmos/cosmos-sdk/pull/12693) Fix non-deterministic map iteration. ## [v0.46.0-rc1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.46.0-rc1) - 2022-05-23 From 0ae4cc8be208d75e747bb6daf3de1a9ce655df23 Mon Sep 17 00:00:00 2001 From: bruce-wayne2 Date: Tue, 26 Jul 2022 11:02:53 +0800 Subject: [PATCH 3/4] use generic functions to sort map --- types/events.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/types/events.go b/types/events.go index 322186f5e9c2..2d295bebc09a 100644 --- a/types/events.go +++ b/types/events.go @@ -3,6 +3,8 @@ package types import ( "encoding/json" "fmt" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" "reflect" "sort" "strings" @@ -88,7 +90,8 @@ func TypedEventToEvent(tev proto.Message) (Event, error) { } // sort the keys to ensure the order is always the same - keys := orderedKeys(attrMap) + keys := maps.Keys(attrMap) + slices.Sort(keys) attrs := make([]abci.EventAttribute, 0, len(attrMap)) for _, k := range keys { @@ -105,15 +108,6 @@ func TypedEventToEvent(tev proto.Message) (Event, error) { }, nil } -func orderedKeys(m map[string]json.RawMessage) []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return keys -} - // ParseTypedEvent converts abci.Event back to typed event func ParseTypedEvent(event abci.Event) (proto.Message, error) { concreteGoType := proto.MessageType(event.Type) From c2fedde5b2c1cc1155016f2ec62e0fab4714603b Mon Sep 17 00:00:00 2001 From: bruce-wayne2 Date: Tue, 26 Jul 2022 11:05:09 +0800 Subject: [PATCH 4/4] update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cfe45a84b40..527a7a4ac54d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [#12453](https://github.com/cosmos/cosmos-sdk/pull/12453) Add `NewInMemoryWithKeyring` function which allows the creation of in memory `keystore` instances with a specified set of existing items. * [#11390](https://github.com/cosmos/cosmos-sdk/pull/11390) `LatestBlockResponse` & `BlockByHeightResponse` types' `Block` filed has been deprecated and they now contains new field `sdk_block` with `proposer_address` as `string` * [#12626](https://github.com/cosmos/cosmos-sdk/pull/12626) Upgrade IAVL to v0.19.0 with fast index and error propagation. NOTE: first start will take a while to propagate into new model. +* [#12693](https://github.com/cosmos/cosmos-sdk/pull/12693) Make sure the order of each node is consistent when emitting proto events. ### State Machine Breaking @@ -118,7 +119,6 @@ empty coins slice before it is used to create `banktype.MsgSend`. * (x/auth/tx) [#12474](https://github.com/cosmos/cosmos-sdk/pull/12474) Remove condition in GetTxsEvent that disallowed multiple equal signs, which would break event queries with base64 strings (i.e. query by signature). * [#12448](https://github.com/cosmos/cosmos-sdk/pull/12448) Start telemetry independently from the API server. * (store/rootmulti) [#12487](https://github.com/cosmos/cosmos-sdk/pull/12487) Fix non-deterministic map iteration. -* (types) [#12693](https://github.com/cosmos/cosmos-sdk/pull/12693) Fix non-deterministic map iteration. ## [v0.46.0-rc1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.46.0-rc1) - 2022-05-23