From 84be89973ac0cff7b9a48fec257dce1424c3a1c2 Mon Sep 17 00:00:00 2001 From: unknown unknown Date: Mon, 17 Jul 2023 11:31:37 +0200 Subject: [PATCH 1/9] add triple --- collections/triple.go | 310 +++++++++++++++++++++++++++++++++++++ collections/triple_test.go | 51 ++++++ 2 files changed, 361 insertions(+) create mode 100644 collections/triple.go create mode 100644 collections/triple_test.go diff --git a/collections/triple.go b/collections/triple.go new file mode 100644 index 000000000000..b465b25b877d --- /dev/null +++ b/collections/triple.go @@ -0,0 +1,310 @@ +package collections + +import ( + "encoding/json" + "fmt" + "strings" + + "cosmossdk.io/collections/codec" +) + +// Triple defines a multipart key composed of three keys. +type Triple[K1, K2, K3 any] struct { + k1 *K1 + k2 *K2 + k3 *K3 +} + +// Join3 instantiates a new Triple instance composed of the three provided keys, in order. +func Join3[K1, K2, K3 any](k1 K1, k2 K2, k3 K3) Triple[K1, K2, K3] { + return Triple[K1, K2, K3]{&k1, &k2, &k3} +} + +// K1 returns the first part of the key. If nil, the zero value is returned. +func (t Triple[K1, K2, K3]) K1() (x K1) { + if t.k1 != nil { + return *t.k1 + } + return x +} + +// K2 returns the second part of the key. If nil, the zero value is returned. +func (t Triple[K1, K2, K3]) K2() (x K2) { + if t.k2 != nil { + return *t.k2 + } + return x +} + +// K3 returns the third part of the key. If nil, the zero value is returned. +func (t Triple[K1, K2, K3]) K3() (x K3) { + if t.k3 != nil { + return *t.k3 + } + return x +} + +// TriplePrefix creates a new Triple instance composed only of the first part of the key. +func TriplePrefix[K1, K2, K3 any](k1 K1) Triple[K1, K2, K3] { + return Triple[K1, K2, K3]{k1: &k1} +} + +// TripleSuperPrefix creates a new Triple instance composed only of the first two parts of the key. +func TripleSuperPrefix[K1, K2, K3 any](k1 K1, k2 K2) Triple[K1, K2, K3] { + return Triple[K1, K2, K3]{k1: &k1, k2: &k2} +} + +// TripleKeyCodec instantiates a new KeyCodec instance that can encode the Triple, given +// the KeyCodecs of the three parts of the key, in order. +func TripleKeyCodec[K1, K2, K3 any](keyCodec1 codec.KeyCodec[K1], keyCodec2 codec.KeyCodec[K2], keyCodec3 codec.KeyCodec[K3]) codec.KeyCodec[Triple[K1, K2, K3]] { + return tripleKeyCodec[K1, K2, K3]{ + keyCodec1: keyCodec1, + keyCodec2: keyCodec2, + keyCodec3: keyCodec3, + } +} + +type tripleKeyCodec[K1, K2, K3 any] struct { + keyCodec1 codec.KeyCodec[K1] + keyCodec2 codec.KeyCodec[K2] + keyCodec3 codec.KeyCodec[K3] +} + +type jsonTripleKey [3]json.RawMessage + +func (t tripleKeyCodec[K1, K2, K3]) EncodeJSON(value Triple[K1, K2, K3]) ([]byte, error) { + json1, err := t.keyCodec1.EncodeJSON(*value.k1) + if err != nil { + return nil, err + } + + json2, err := t.keyCodec2.EncodeJSON(*value.k2) + if err != nil { + return nil, err + } + + json3, err := t.keyCodec3.EncodeJSON(*value.k3) + if err != nil { + return nil, err + } + + return json.Marshal(jsonTripleKey{json1, json2, json3}) +} + +func (t tripleKeyCodec[K1, K2, K3]) DecodeJSON(b []byte) (Triple[K1, K2, K3], error) { + var jsonKey jsonTripleKey + err := json.Unmarshal(b, &jsonKey) + if err != nil { + return Triple[K1, K2, K3]{}, err + } + + key1, err := t.keyCodec1.DecodeJSON(jsonKey[0]) + if err != nil { + return Triple[K1, K2, K3]{}, err + } + + key2, err := t.keyCodec2.DecodeJSON(jsonKey[1]) + if err != nil { + return Triple[K1, K2, K3]{}, err + } + + key3, err := t.keyCodec3.DecodeJSON(jsonKey[2]) + if err != nil { + return Triple[K1, K2, K3]{}, err + } + + return Join3(key1, key2, key3), nil +} + +func (t tripleKeyCodec[K1, K2, K3]) Stringify(key Triple[K1, K2, K3]) string { + b := new(strings.Builder) + b.WriteByte('(') + if key.k1 != nil { + b.WriteByte('"') + b.WriteString(t.keyCodec1.Stringify(*key.k1)) + b.WriteByte('"') + } else { + b.WriteString("") + } + + b.WriteString(", ") + if key.k2 != nil { + b.WriteByte('"') + b.WriteString(t.keyCodec2.Stringify(*key.k2)) + b.WriteByte('"') + } else { + b.WriteString("") + } + + b.WriteString(", ") + if key.k3 != nil { + b.WriteByte('"') + b.WriteString(t.keyCodec3.Stringify(*key.k3)) + b.WriteByte('"') + } else { + b.WriteString("") + } + + b.WriteByte(')') + return b.String() +} + +func (t tripleKeyCodec[K1, K2, K3]) KeyType() string { + return fmt.Sprintf("Triple[%s,%s,%s]", t.keyCodec1.KeyType(), t.keyCodec2.KeyType(), t.keyCodec3.KeyType()) +} + +func (t tripleKeyCodec[K1, K2, K3]) Encode(buffer []byte, key Triple[K1, K2, K3]) (int, error) { + writtenTotal := 0 + if key.k1 != nil { + written, err := t.keyCodec1.EncodeNonTerminal(buffer, *key.k1) + if err != nil { + return 0, err + } + writtenTotal += written + } + if key.k2 != nil { + written, err := t.keyCodec2.EncodeNonTerminal(buffer[writtenTotal:], *key.k2) + if err != nil { + return 0, err + } + writtenTotal += written + } + if key.k3 != nil { + written, err := t.keyCodec3.Encode(buffer[writtenTotal:], *key.k3) + if err != nil { + return 0, err + } + writtenTotal += written + } + return writtenTotal, nil +} + +func (t tripleKeyCodec[K1, K2, K3]) Decode(buffer []byte) (int, Triple[K1, K2, K3], error) { + readTotal := 0 + read, key1, err := t.keyCodec1.DecodeNonTerminal(buffer) + if err != nil { + return 0, Triple[K1, K2, K3]{}, err + } + readTotal += read + read, key2, err := t.keyCodec2.DecodeNonTerminal(buffer[readTotal:]) + if err != nil { + return 0, Triple[K1, K2, K3]{}, err + } + readTotal += read + read, key3, err := t.keyCodec3.Decode(buffer[readTotal:]) + if err != nil { + return 0, Triple[K1, K2, K3]{}, err + } + readTotal += read + return readTotal, Join3(key1, key2, key3), nil +} + +func (t tripleKeyCodec[K1, K2, K3]) Size(key Triple[K1, K2, K3]) int { + size := 0 + if key.k1 != nil { + size += t.keyCodec1.SizeNonTerminal(*key.k1) + } + if key.k2 != nil { + size += t.keyCodec2.SizeNonTerminal(*key.k2) + } + if key.k3 != nil { + size += t.keyCodec3.Size(*key.k3) + } + return size +} + +func (t tripleKeyCodec[K1, K2, K3]) EncodeNonTerminal(buffer []byte, key Triple[K1, K2, K3]) (int, error) { + writtenTotal := 0 + if key.k1 != nil { + written, err := t.keyCodec1.EncodeNonTerminal(buffer, *key.k1) + if err != nil { + return 0, err + } + writtenTotal += written + } + if key.k2 != nil { + written, err := t.keyCodec2.EncodeNonTerminal(buffer[writtenTotal:], *key.k2) + if err != nil { + return 0, err + } + writtenTotal += written + } + if key.k3 != nil { + written, err := t.keyCodec3.EncodeNonTerminal(buffer[writtenTotal:], *key.k3) + if err != nil { + return 0, err + } + writtenTotal += written + } + return writtenTotal, nil +} + +func (t tripleKeyCodec[K1, K2, K3]) DecodeNonTerminal(buffer []byte) (int, Triple[K1, K2, K3], error) { + readTotal := 0 + read, key1, err := t.keyCodec1.DecodeNonTerminal(buffer) + if err != nil { + return 0, Triple[K1, K2, K3]{}, err + } + readTotal += read + read, key2, err := t.keyCodec2.DecodeNonTerminal(buffer[readTotal:]) + if err != nil { + return 0, Triple[K1, K2, K3]{}, err + } + readTotal += read + read, key3, err := t.keyCodec3.DecodeNonTerminal(buffer[readTotal:]) + if err != nil { + return 0, Triple[K1, K2, K3]{}, err + } + readTotal += read + return readTotal, Join3(key1, key2, key3), nil +} + +func (t tripleKeyCodec[K1, K2, K3]) SizeNonTerminal(key Triple[K1, K2, K3]) int { + size := 0 + if key.k1 != nil { + size += t.keyCodec1.SizeNonTerminal(*key.k1) + } + if key.k2 != nil { + size += t.keyCodec2.SizeNonTerminal(*key.k2) + } + if key.k3 != nil { + size += t.keyCodec3.SizeNonTerminal(*key.k3) + } + return size +} + +func PrefixTripleRange[K1, K2, K3 any](k1 K1) Ranger[Triple[K1, K2, K3]] { + key := TriplePrefix[K1, K2, K3](k1) + return &Range[Triple[K1, K2, K3]]{ + start: RangeKeyExact(key), + end: RangeKeyPrefixEnd(key), + } +} + +func SuperPrefixTripleRange[K1, K2, K3 any](k1 K1, k2 K2) Ranger[Triple[K1, K2, K3]] { + key := TripleSuperPrefix[K1, K2, K3](k1, k2) + return &Range[Triple[K1, K2, K3]]{ + start: RangeKeyExact(key), + end: RangeKeyPrefixEnd(key), + } +} + +// NewPrefixedTripleRange provides a Range for all keys prefixed with the given +// first part of the Triple key. +func NewPrefixedTripleRange[K1, K2, K3 any](prefix K1) Ranger[Triple[K1, K2, K3]] { + key := TriplePrefix[K1, K2, K3](prefix) + return &Range[Triple[K1, K2, K3]]{ + start: RangeKeyExact(key), + end: RangeKeyPrefixEnd(key), + } +} + +// NewSuperPrefixedTripleRange provides a Range for all keys prefixed with the given +// first and second parts of the Triple key. +func NewSuperPrefixedTripleRange[K1, K2, K3 any](k1 K1, k2 K2) Ranger[Triple[K1, K2, K3]] { + key := TripleSuperPrefix[K1, K2, K3](k1, k2) + return &Range[Triple[K1, K2, K3]]{ + start: RangeKeyExact(key), + end: RangeKeyPrefixEnd(key), + } +} diff --git a/collections/triple_test.go b/collections/triple_test.go new file mode 100644 index 000000000000..11e03b665f6d --- /dev/null +++ b/collections/triple_test.go @@ -0,0 +1,51 @@ +package collections_test + +import ( + "testing" + + "cosmossdk.io/collections" + "cosmossdk.io/collections/colltest" + "github.com/stretchr/testify/require" +) + +func TestTriple(t *testing.T) { + kc := collections.TripleKeyCodec(collections.Uint64Key, collections.StringKey, collections.BytesKey) + + t.Run("conformance", func(t *testing.T) { + colltest.TestKeyCodec(t, kc, collections.Join3(uint64(1), "2", []byte("3"))) + }) +} + +func TestTripleRange(t *testing.T) { + sk, ctx := colltest.MockStore() + schema := collections.NewSchemaBuilder(sk) + // this is a key composed of 3 parts: uint64, string, []byte + kc := collections.TripleKeyCodec(collections.Uint64Key, collections.StringKey, collections.BytesKey) + + keySet := collections.NewKeySet(schema, collections.NewPrefix(0), "triple", kc) + + keys := []collections.Triple[uint64, string, []byte]{ + collections.Join3(uint64(1), "A", []byte("1")), + collections.Join3(uint64(1), "A", []byte("2")), + collections.Join3(uint64(1), "B", []byte("3")), + collections.Join3(uint64(2), "B", []byte("4")), + } + + for _, k := range keys { + require.NoError(t, keySet.Set(ctx, k)) + } + + // we prefix over (1) we expect 3 results + iter, err := keySet.Iterate(ctx, collections.NewPrefixedTripleRange[uint64, string, []byte](uint64(1))) + require.NoError(t, err) + gotKeys, err := iter.Keys() + require.NoError(t, err) + require.Equal(t, keys[:3], gotKeys) + + // we super prefix over Join(1, "A") we expect 2 results + iter, err = keySet.Iterate(ctx, collections.NewSuperPrefixedTripleRange[uint64, string, []byte](1, "A")) + require.NoError(t, err) + gotKeys, err = iter.Keys() + require.NoError(t, err) + require.Equal(t, keys[:2], gotKeys) +} From 7f7fdcbedf2d1697f42f11d09336cb731a18f075 Mon Sep 17 00:00:00 2001 From: unknown unknown Date: Mon, 17 Jul 2023 11:50:53 +0200 Subject: [PATCH 2/9] update readme --- collections/README.md | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/collections/README.md b/collections/README.md index bd25d2e1cccf..9e05b1341817 100644 --- a/collections/README.md +++ b/collections/README.md @@ -1118,6 +1118,58 @@ func (k Keeper) GetAccount(ctx sdk.context, addr sdk.AccAddress) (sdk.AccountI, } ``` +## Triple key + +The `collections.Triple` is a special type of key that allows to index a collection using three different keys. + +Let's see an example. + +```go +package example + +import ( + "context" + + "cosmossdk.io/collections" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" +) + +type AccAddress = string +type ValAddress = string + +type Keeper struct { + // let's simulate we have redelegations which are stored as a triple key composed of + // the delegator, the source validator and the destination validator. + Redelegations collections.KeySet[collections.Triple[AccAddress, ValAddress, ValAddress]] +} + +func NewKeeper(storeKey *storetypes.KVStoreKey) Keeper { + sb := collections.NewSchemaBuilder(sdk.OpenKVStore(storeKey)) + return Keeper{ + Redelegations: collections.NewKeySet(sb, collections.NewPrefix(0), "redelegations", collections.TripleKeyCodec(collections.StringKey, collections.StringKey, collections.StringKey) + } +} + +// RedelegationsByDelegator iterates over all the redelegations of a given delegator and calls onResult providing +// each redelegation from source validator towards the destination validator. +func (k Keeper) RedelegationsByDelegator(ctx context.Context, delegator AccAddress, onResult func(src, dst ValAddress) (stop bool, err error)) error { + rng := collections.NewPrefixedTripleRange[AccAddress, ValAddress, ValAddress](delegator) + return k.Redelegations.Walk(ctx, rng, func(key collections.Triple[AccAddress, ValAddress, ValAddress]) (stop bool, err error) { + return onResult(key.K2(), key.K3()) + }) +} + +// RedelegationsByDelegatorAndValidator iterates over all the redelegations of a given delegator and its source validator and calls onResult for each +// destination validator. +func (k Keeper) RedelegationsByDelegatorAndValidator(ctx context.Context, delegator AccAddress, validator ValAddress, onResult func(dst ValAddress) (stop bool, err error)) error { + rng := collections.NewSuperPrefixedTripleRange[AccAddress, ValAddress, ValAddress](delegator, validator) + return k.Redelegations.Walk(ctx, rng, func(key collections.Triple[AccAddress, ValAddress, ValAddress]) (stop bool, err error) { + return onResult(key.K3()) + }) +} +``` + ## Advanced Usages ### Alternative Value Codec From b7e3622025fe4966c6bde417c17bdec34bf673c9 Mon Sep 17 00:00:00 2001 From: unknown unknown Date: Mon, 17 Jul 2023 12:05:15 +0200 Subject: [PATCH 3/9] fix readme --- collections/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collections/README.md b/collections/README.md index 9e05b1341817..72d5f7172a58 100644 --- a/collections/README.md +++ b/collections/README.md @@ -1120,7 +1120,7 @@ func (k Keeper) GetAccount(ctx sdk.context, addr sdk.AccAddress) (sdk.AccountI, ## Triple key -The `collections.Triple` is a special type of key that allows to index a collection using three different keys. +The `collections.Triple` is a special type of key composed of three keys, it's identical to `collections.Pair`. Let's see an example. From a73b17db034cb7e47cdc5f9a3cbad7d8714e0b23 Mon Sep 17 00:00:00 2001 From: unknown unknown Date: Mon, 17 Jul 2023 12:06:38 +0200 Subject: [PATCH 4/9] chore: CHANGELOG.md --- collections/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/collections/CHANGELOG.md b/collections/CHANGELOG.md index 92a7e92c5890..9b04bc86e9cd 100644 --- a/collections/CHANGELOG.md +++ b/collections/CHANGELOG.md @@ -29,6 +29,12 @@ Ref: https://keepachangelog.com/en/1.0.0/ # Changelog +## [Unreleased] + +### Features + +* [#17024](https://github.com/cosmos/cosmos-sdk/pull/17024) - Introduces `Triple`, a composite key with three keys. + ## [v0.3.0](https://github.com/cosmos/cosmos-sdk/releases/tag/collections%2Fv0.3.0) ### Features From b530571c551992a933467e6fe9f36479c5613840 Mon Sep 17 00:00:00 2001 From: unknown unknown Date: Mon, 17 Jul 2023 12:11:14 +0200 Subject: [PATCH 5/9] lint --- collections/triple_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/collections/triple_test.go b/collections/triple_test.go index 11e03b665f6d..fea1b662c15c 100644 --- a/collections/triple_test.go +++ b/collections/triple_test.go @@ -3,9 +3,10 @@ package collections_test import ( "testing" + "github.com/stretchr/testify/require" + "cosmossdk.io/collections" "cosmossdk.io/collections/colltest" - "github.com/stretchr/testify/require" ) func TestTriple(t *testing.T) { From 405cf4e35f775e065170f869b097cec738693221 Mon Sep 17 00:00:00 2001 From: unknown unknown Date: Tue, 18 Jul 2023 14:26:02 +0200 Subject: [PATCH 6/9] add protov2 value encoder --- codec/collections.go | 55 ++++++++++++++++++++++++++++++++++++--- codec/collections_test.go | 22 ++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/codec/collections.go b/codec/collections.go index c58da9cb8ea4..81eefc725054 100644 --- a/codec/collections.go +++ b/codec/collections.go @@ -6,6 +6,8 @@ import ( "github.com/cosmos/gogoproto/proto" gogotypes "github.com/cosmos/gogoproto/types" + "google.golang.org/protobuf/encoding/protojson" + protov2 "google.golang.org/protobuf/proto" "cosmossdk.io/collections" collcodec "cosmossdk.io/collections/codec" @@ -51,10 +53,13 @@ type protoMessage[T any] interface { // CollValue inits a collections.ValueCodec for a generic gogo protobuf message. func CollValue[T any, PT protoMessage[T]](cdc BinaryCodec) collcodec.ValueCodec[T] { - return &collValue[T, PT]{cdc.(Codec)} + return &collValue[T, PT]{cdc.(Codec), proto.MessageName(PT(new(T)))} } -type collValue[T any, PT protoMessage[T]] struct{ cdc Codec } +type collValue[T any, PT protoMessage[T]] struct { + cdc Codec + messageName string +} func (c collValue[T, PT]) Encode(value T) ([]byte, error) { return c.cdc.Marshal(PT(&value)) @@ -79,7 +84,51 @@ func (c collValue[T, PT]) Stringify(value T) string { } func (c collValue[T, PT]) ValueType() string { - return "gogoproto/" + proto.MessageName(PT(new(T))) + return "github.com/gogo/protobuf/" + c.messageName +} + +type protoMessageV2[T any] interface { + *T + protov2.Message +} + +// CollValueV2 is used for protobuf values of the newest google.golang.org/protobuf API. +func CollValueV2[T any, PT protoMessageV2[T]]() collcodec.ValueCodec[PT] { + return &collValue2[T, PT]{ + messageName: string(PT(new(T)).ProtoReflect().Descriptor().FullName()), + } +} + +type collValue2[T any, PT protoMessageV2[T]] struct { + messageName string +} + +func (c collValue2[T, PT]) Encode(value PT) ([]byte, error) { + return protov2.Marshal(value) +} + +func (c collValue2[T, PT]) Decode(b []byte) (PT, error) { + var value T + err := protov2.Unmarshal(b, PT(&value)) + return &value, err +} + +func (c collValue2[T, PT]) EncodeJSON(value PT) ([]byte, error) { + return protojson.Marshal(value) +} + +func (c collValue2[T, PT]) DecodeJSON(b []byte) (PT, error) { + var value T + err := protojson.Unmarshal(b, PT(&value)) + return &value, err +} + +func (c collValue2[T, PT]) Stringify(value PT) string { + return fmt.Sprintf("%v", value) +} + +func (c collValue2[T, PT]) ValueType() string { + return "google.golang.org/protobuf/" + c.messageName } // CollInterfaceValue instantiates a new collections.ValueCodec for a generic diff --git a/codec/collections_test.go b/codec/collections_test.go index 3183c9228a0b..a71d14a9a9e2 100644 --- a/codec/collections_test.go +++ b/codec/collections_test.go @@ -4,7 +4,10 @@ import ( "testing" gogotypes "github.com/cosmos/gogoproto/types" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/wrapperspb" "cosmossdk.io/collections/colltest" @@ -21,6 +24,25 @@ func TestCollectionsCorrectness(t *testing.T) { }) }) + t.Run("CollValueV2", func(t *testing.T) { + encoder := codec.CollValueV2[wrapperspb.UInt64Value]() + value := &wrapperspb.UInt64Value{Value: 500} + encodedValue, err := encoder.Encode(value) + require.NoError(t, err) + decodedValue, err := encoder.Decode(encodedValue) + require.NoError(t, err) + require.True(t, cmp.Equal(value, decodedValue, protocmp.Transform()), "encoding and decoding produces different values") + + encodedJSONValue, err := encoder.EncodeJSON(value) + require.NoError(t, err) + decodedJSONValue, err := encoder.DecodeJSON(encodedJSONValue) + require.NoError(t, err) + require.True(t, cmp.Equal(value, decodedJSONValue, protocmp.Transform()), "encoding and decoding produces different values") + require.NotEmpty(t, encoder.ValueType()) + + _ = encoder.Stringify(value) + }) + t.Run("BoolValue", func(t *testing.T) { colltest.TestValueCodec(t, codec.BoolValue, true) colltest.TestValueCodec(t, codec.BoolValue, false) From 9d1d2c77bd4dc9d121157f5c6ff633316867150e Mon Sep 17 00:00:00 2001 From: unknown unknown Date: Tue, 18 Jul 2023 14:26:48 +0200 Subject: [PATCH 7/9] chore doc --- codec/collections_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/codec/collections_test.go b/codec/collections_test.go index a71d14a9a9e2..5aff0e0e06df 100644 --- a/codec/collections_test.go +++ b/codec/collections_test.go @@ -25,6 +25,9 @@ func TestCollectionsCorrectness(t *testing.T) { }) t.Run("CollValueV2", func(t *testing.T) { + // NOTE: we cannot use colltest.TestValueCodec because protov2 has different + // compare semantics than protov1. We need to use protocmp.Transform() alongside + // cmp to ensure equality. encoder := codec.CollValueV2[wrapperspb.UInt64Value]() value := &wrapperspb.UInt64Value{Value: 500} encodedValue, err := encoder.Encode(value) From 04726b7f777a53e8d452675c3acee09091496bcb Mon Sep 17 00:00:00 2001 From: unknown unknown Date: Tue, 18 Jul 2023 14:37:15 +0200 Subject: [PATCH 8/9] chore CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a06a112ad63..f9be5245629b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (baseapp) [#16898](https://github.com/cosmos/cosmos-sdk/pull/16898) Add `preFinalizeBlockHook` to allow vote extensions persistence. * (cli) [#16887](https://github.com/cosmos/cosmos-sdk/pull/16887) Add two new CLI commands: `tx simulate` for simulating a transaction; `query block-results` for querying CometBFT RPC for block results. * (x/gov) [#16976](https://github.com/cosmos/cosmos-sdk/pull/16976) Add `failed_reason` field to `Proposal` under `x/gov` to indicate the reason for a failed proposal. Referenced from [#238](https://github.com/bnb-chain/greenfield-cosmos-sdk/pull/238) under `bnb-chain/greenfield-cosmos-sdk`. +* (codec) [#17042](https://github.com/cosmos/cosmos-sdk/pull/17042) Add `CollValueV2` which supports encoding of protov2 messages in collections. ### Improvements From fd8820ab7cc13385abeb2bebfa637db2106996eb Mon Sep 17 00:00:00 2001 From: unknown unknown Date: Tue, 18 Jul 2023 16:19:01 +0200 Subject: [PATCH 9/9] value type --- codec/collections.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codec/collections.go b/codec/collections.go index 81eefc725054..12f1c396d5c8 100644 --- a/codec/collections.go +++ b/codec/collections.go @@ -84,7 +84,7 @@ func (c collValue[T, PT]) Stringify(value T) string { } func (c collValue[T, PT]) ValueType() string { - return "github.com/gogo/protobuf/" + c.messageName + return "github.com/cosmos/gogoproto/" + c.messageName } type protoMessageV2[T any] interface {