diff --git a/codec/collections.go b/codec/collections.go index 3e93b22b1d..f34b0dcb17 100644 --- a/codec/collections.go +++ b/codec/collections.go @@ -1,10 +1,47 @@ package codec import ( + gogotypes "github.com/cosmos/gogoproto/types" + + "cosmossdk.io/collections" collcodec "cosmossdk.io/collections/codec" + "github.com/cosmos/gogoproto/proto" ) +// BoolValue implements a ValueCodec that saves the bool value +// as if it was a prototypes.BoolValue. Required for backwards +// compatibility of state. +var BoolValue collcodec.ValueCodec[bool] = boolValue{} + +type boolValue struct{} + +func (boolValue) Encode(value bool) ([]byte, error) { + return (&gogotypes.BoolValue{Value: value}).Marshal() +} + +func (boolValue) Decode(b []byte) (bool, error) { + v := new(gogotypes.BoolValue) + err := v.Unmarshal(b) + return v.Value, err +} + +func (boolValue) EncodeJSON(value bool) ([]byte, error) { + return collections.BoolValue.EncodeJSON(value) +} + +func (boolValue) DecodeJSON(b []byte) (bool, error) { + return collections.BoolValue.DecodeJSON(b) +} + +func (boolValue) Stringify(value bool) string { + return collections.BoolValue.Stringify(value) +} + +func (boolValue) ValueType() string { + return "protobuf/bool" +} + type protoMessage[T any] interface { *T proto.Message diff --git a/codec/collections_test.go b/codec/collections_test.go index bd01a758d6..6352738933 100644 --- a/codec/collections_test.go +++ b/codec/collections_test.go @@ -3,16 +3,35 @@ package codec import ( "testing" + "github.com/stretchr/testify/require" + "cosmossdk.io/collections/colltest" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/gogoproto/types" + gogotypes "github.com/cosmos/gogoproto/types" ) func TestCollectionsCorrectness(t *testing.T) { cdc := NewProtoCodec(codectypes.NewInterfaceRegistry()) t.Run("CollValue", func(t *testing.T) { - colltest.TestValueCodec(t, CollValue[types.UInt64Value](cdc), types.UInt64Value{ + colltest.TestValueCodec(t, CollValue[gogotypes.UInt64Value](cdc), gogotypes.UInt64Value{ Value: 500, }) }) + + t.Run("BoolValue", func(t *testing.T) { + colltest.TestValueCodec(t, BoolValue, true) + colltest.TestValueCodec(t, BoolValue, false) + + // asserts produced bytes are equal + valueAssert := func(b bool) { + wantBytes, err := (&gogotypes.BoolValue{Value: b}).Marshal() + require.NoError(t, err) + gotBytes, err := BoolValue.Encode(b) + require.NoError(t, err) + require.Equal(t, wantBytes, gotBytes) + } + + valueAssert(true) + valueAssert(false) + }) } diff --git a/go.mod b/go.mod index ee26079649..9846ec7ee1 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ module github.com/cosmos/cosmos-sdk require ( cosmossdk.io/api v0.3.1 - cosmossdk.io/collections v0.0.0-20230214153846-b6c6e4e99177 + cosmossdk.io/collections v0.0.0-20230306161821-d6240a43e6e8 cosmossdk.io/core v0.6.0 cosmossdk.io/depinject v1.0.0-alpha.3 cosmossdk.io/errors v1.0.0-beta.7 @@ -107,9 +107,7 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect diff --git a/go.sum b/go.sum index 5655177200..104b9463d1 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cosmossdk.io/api v0.3.1 h1:NNiOclKRR0AOlO4KIqeaG6PS6kswOMhHD0ir0SscNXE= cosmossdk.io/api v0.3.1/go.mod h1:DfHfMkiNA2Uhy8fj0JJlOCYOBp4eWUUJ1te5zBGNyIw= -cosmossdk.io/collections v0.0.0-20230214153846-b6c6e4e99177 h1:At2M0aYQKEAWqr6JtZrJPOlfhdvENiGwJg2NCNHwIdc= -cosmossdk.io/collections v0.0.0-20230214153846-b6c6e4e99177/go.mod h1:uqCi8FG+Bh2vv/qf5xZ8iab0E0c/DMA/cwafbp8dkcU= +cosmossdk.io/collections v0.0.0-20230306161821-d6240a43e6e8 h1:TmhLZxHM/TlyiF1bS7ObHBzMdXW0nEJC3i+nQ/nt4Zs= +cosmossdk.io/collections v0.0.0-20230306161821-d6240a43e6e8/go.mod h1:RoEzMOLLsorYvlNTm1wzYzlI5yQ0QSWeJqkMdfDVgHE= cosmossdk.io/core v0.6.0 h1:V2zyaMVFN6hJSVENYx2XE9CMhzqwJPMjzSQpj0MyXAU= cosmossdk.io/core v0.6.0/go.mod h1:YSFzBcKOf/U24e/sa6WFaYSrlZl5zgNvnWwjfFyPniw= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= @@ -446,8 +446,6 @@ github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIv github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -455,8 +453,6 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= diff --git a/runtime/store.go b/runtime/store.go index e06323c581..ed4a11dda1 100644 --- a/runtime/store.go +++ b/runtime/store.go @@ -10,6 +10,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +func NewKVStoreService(storeKey *storetypes.KVStoreKey) store.KVStoreService { + return &kvStoreService{key: storeKey} +} + type kvStoreService struct { key *storetypes.KVStoreKey } diff --git a/simapp/go.mod b/simapp/go.mod index 7f87498506..1585e05121 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -36,7 +36,7 @@ require ( cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v0.11.0 // indirect cloud.google.com/go/storage v1.29.0 // indirect - cosmossdk.io/collections v0.0.0-20230214153846-b6c6e4e99177 // indirect + cosmossdk.io/collections v0.0.0-20230306161821-d6240a43e6e8 // indirect cosmossdk.io/errors v1.0.0-beta.7 // indirect cosmossdk.io/x/tx v0.2.2 // indirect filippo.io/edwards25519 v1.0.0 // indirect @@ -108,11 +108,9 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter v1.7.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect diff --git a/simapp/go.sum b/simapp/go.sum index b31c4e0014..4b4ea4de2b 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -192,8 +192,8 @@ cosmossdk.io/api v0.3.1 h1:NNiOclKRR0AOlO4KIqeaG6PS6kswOMhHD0ir0SscNXE= cosmossdk.io/api v0.3.1/go.mod h1:DfHfMkiNA2Uhy8fj0JJlOCYOBp4eWUUJ1te5zBGNyIw= cosmossdk.io/client/v2 v2.0.0-20230220152935-67f04e629623 h1:QzZA1P+twvj10ylCVXzHodLge+RvrwoNIlWpU+MrRa0= cosmossdk.io/client/v2 v2.0.0-20230220152935-67f04e629623/go.mod h1:Yo6R3XSXKxi+G642kK7+ZOh2czNTwTO1b8ywOvwaFQo= -cosmossdk.io/collections v0.0.0-20230214153846-b6c6e4e99177 h1:At2M0aYQKEAWqr6JtZrJPOlfhdvENiGwJg2NCNHwIdc= -cosmossdk.io/collections v0.0.0-20230214153846-b6c6e4e99177/go.mod h1:uqCi8FG+Bh2vv/qf5xZ8iab0E0c/DMA/cwafbp8dkcU= +cosmossdk.io/collections v0.0.0-20230306161821-d6240a43e6e8 h1:TmhLZxHM/TlyiF1bS7ObHBzMdXW0nEJC3i+nQ/nt4Zs= +cosmossdk.io/collections v0.0.0-20230306161821-d6240a43e6e8/go.mod h1:RoEzMOLLsorYvlNTm1wzYzlI5yQ0QSWeJqkMdfDVgHE= cosmossdk.io/core v0.6.0 h1:V2zyaMVFN6hJSVENYx2XE9CMhzqwJPMjzSQpj0MyXAU= cosmossdk.io/core v0.6.0/go.mod h1:YSFzBcKOf/U24e/sa6WFaYSrlZl5zgNvnWwjfFyPniw= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= @@ -645,8 +645,6 @@ github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIv github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= @@ -658,8 +656,6 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= diff --git a/tests/go.mod b/tests/go.mod index 2ab3f36d99..cd5cfa5277 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -37,7 +37,7 @@ require ( cloud.google.com/go/iam v0.11.0 // indirect cloud.google.com/go/storage v1.29.0 // indirect cosmossdk.io/client/v2 v2.0.0-20230220152935-67f04e629623 // indirect - cosmossdk.io/collections v0.0.0-20230214153846-b6c6e4e99177 // indirect + cosmossdk.io/collections v0.0.0-20230306161821-d6240a43e6e8 // indirect cosmossdk.io/core v0.6.0 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect @@ -102,11 +102,9 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter v1.7.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect diff --git a/tests/go.sum b/tests/go.sum index fb10c1ff37..7f22034336 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -190,8 +190,8 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/api v0.3.1 h1:NNiOclKRR0AOlO4KIqeaG6PS6kswOMhHD0ir0SscNXE= cosmossdk.io/api v0.3.1/go.mod h1:DfHfMkiNA2Uhy8fj0JJlOCYOBp4eWUUJ1te5zBGNyIw= -cosmossdk.io/collections v0.0.0-20230214153846-b6c6e4e99177 h1:At2M0aYQKEAWqr6JtZrJPOlfhdvENiGwJg2NCNHwIdc= -cosmossdk.io/collections v0.0.0-20230214153846-b6c6e4e99177/go.mod h1:uqCi8FG+Bh2vv/qf5xZ8iab0E0c/DMA/cwafbp8dkcU= +cosmossdk.io/collections v0.0.0-20230306161821-d6240a43e6e8 h1:TmhLZxHM/TlyiF1bS7ObHBzMdXW0nEJC3i+nQ/nt4Zs= +cosmossdk.io/collections v0.0.0-20230306161821-d6240a43e6e8/go.mod h1:RoEzMOLLsorYvlNTm1wzYzlI5yQ0QSWeJqkMdfDVgHE= cosmossdk.io/core v0.6.0 h1:V2zyaMVFN6hJSVENYx2XE9CMhzqwJPMjzSQpj0MyXAU= cosmossdk.io/core v0.6.0/go.mod h1:YSFzBcKOf/U24e/sa6WFaYSrlZl5zgNvnWwjfFyPniw= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= @@ -638,8 +638,6 @@ github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIv github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= @@ -651,8 +649,6 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= diff --git a/types/query/collections_pagination.go b/types/query/collections_pagination.go index 935eaa7582..633efa8ff3 100644 --- a/types/query/collections_pagination.go +++ b/types/query/collections_pagination.go @@ -168,10 +168,13 @@ func collFilteredPaginateNoKey[K, V any, C Collection[K, V]]( count++ } } - return results, &PageResponse{ + resp := &PageResponse{ NextKey: nextKey, - Total: count + offset, - }, nil + } + if countTotal { + resp.Total = count + offset + } + return results, resp, nil } func advanceIter[I interface { diff --git a/x/bank/keeper/grpc_query.go b/x/bank/keeper/grpc_query.go index 65950b5efe..49fa628090 100644 --- a/x/bank/keeper/grpc_query.go +++ b/x/bank/keeper/grpc_query.go @@ -4,7 +4,6 @@ import ( "context" "cosmossdk.io/math" - gogotypes "github.com/cosmos/gogoproto/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -278,32 +277,23 @@ func (k BaseKeeper) SendEnabled(goCtx context.Context, req *types.QuerySendEnabl ctx := sdk.UnwrapSDKContext(goCtx) resp := &types.QuerySendEnabledResponse{} if len(req.Denoms) > 0 { - store := ctx.KVStore(k.storeKey) for _, denom := range req.Denoms { - if se, ok := k.getSendEnabled(store, denom); ok { + if se, ok := k.getSendEnabled(ctx, denom); ok { resp.SendEnabled = append(resp.SendEnabled, types.NewSendEnabled(denom, se)) } } } else { - store := k.getSendEnabledPrefixStore(ctx) - var err error - - resp.Pagination, err = query.FilteredPaginate( - store, - req.Pagination, - func(key []byte, value []byte, accumulate bool) (bool, error) { - if accumulate { - var enabled gogotypes.BoolValue - k.cdc.MustUnmarshal(value, &enabled) - - resp.SendEnabled = append(resp.SendEnabled, types.NewSendEnabled(string(key), enabled.Value)) - } - return true, nil - }, - ) + results, pageResp, err := query.CollectionPaginate[string, bool](ctx, k.BaseViewKeeper.SendEnabled, req.Pagination) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } + for _, r := range results { + resp.SendEnabled = append(resp.SendEnabled, &types.SendEnabled{ + Denom: r.Key, + Enabled: r.Value, + }) + } + resp.Pagination = pageResp } return resp, nil diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index c3c170c483..d767ae5f31 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -6,11 +6,9 @@ import ( "cosmossdk.io/math" errorsmod "cosmossdk.io/errors" - "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/internal/conv" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/query" @@ -67,27 +65,16 @@ type MintingRestrictionFn func(ctx sdk.Context, coins sdk.Coins) error // GetPaginatedTotalSupply queries for the supply, ignoring 0 coins, with a given pagination func (k BaseKeeper) GetPaginatedTotalSupply(ctx sdk.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error) { - store := ctx.KVStore(k.storeKey) - supplyStore := prefix.NewStore(store, types.SupplyKey) - - supply := sdk.NewCoins() - - pageRes, err := query.Paginate(supplyStore, pagination, func(key, value []byte) error { - var amount math.Int - err := amount.Unmarshal(value) - if err != nil { - return fmt.Errorf("unable to convert amount string to Int %v", err) - } - - // `Add` omits the 0 coins addition to the `supply`. - supply = supply.Add(sdk.NewCoin(string(key), amount)) - return nil - }) + results, pageResp, err := query.CollectionPaginate[string, math.Int](ctx, k.Supply, pagination) if err != nil { return nil, nil, err } + coins := sdk.NewCoins() + for _, res := range results { + coins = coins.Add(sdk.NewCoin(res.Key, res.Value)) + } - return supply, pageRes, nil + return coins, pageResp, nil } // NewBaseKeeper returns a new BaseKeeper object with a given codec, dedicated @@ -219,58 +206,30 @@ func (k BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAdd // GetSupply retrieves the Supply from store func (k BaseKeeper) GetSupply(ctx sdk.Context, denom string) sdk.Coin { - store := ctx.KVStore(k.storeKey) - supplyStore := prefix.NewStore(store, types.SupplyKey) - - bz := supplyStore.Get(conv.UnsafeStrToBytes(denom)) - if bz == nil { - return sdk.Coin{ - Denom: denom, - Amount: sdk.NewInt(0), - } - } - - var amount math.Int - err := amount.Unmarshal(bz) + amt, err := k.Supply.Get(ctx, denom) if err != nil { - panic(fmt.Errorf("unable to unmarshal supply value %v", err)) - } - - return sdk.Coin{ - Denom: denom, - Amount: amount, + return sdk.NewCoin(denom, math.ZeroInt()) } + return sdk.NewCoin(denom, amt) } // HasSupply checks if the supply coin exists in store. func (k BaseKeeper) HasSupply(ctx sdk.Context, denom string) bool { - store := ctx.KVStore(k.storeKey) - supplyStore := prefix.NewStore(store, types.SupplyKey) - return supplyStore.Has(conv.UnsafeStrToBytes(denom)) + has, err := k.Supply.Has(ctx, denom) + return has && err == nil } // GetDenomMetaData retrieves the denomination metadata. returns the metadata and true if the denom exists, // false otherwise. func (k BaseKeeper) GetDenomMetaData(ctx sdk.Context, denom string) (types.Metadata, bool) { - store := ctx.KVStore(k.storeKey) - store = prefix.NewStore(store, types.DenomMetadataPrefix) - - bz := store.Get(conv.UnsafeStrToBytes(denom)) - if bz == nil { - return types.Metadata{}, false - } - - var metadata types.Metadata - k.cdc.MustUnmarshal(bz, &metadata) - - return metadata, true + m, err := k.BaseViewKeeper.DenomMetadata.Get(ctx, denom) + return m, err == nil } // HasDenomMetaData checks if the denomination metadata exists in store. func (k BaseKeeper) HasDenomMetaData(ctx sdk.Context, denom string) bool { - store := ctx.KVStore(k.storeKey) - store = prefix.NewStore(store, types.DenomMetadataPrefix) - return store.Has(conv.UnsafeStrToBytes(denom)) + has, err := k.BaseViewKeeper.DenomMetadata.Has(ctx, denom) + return has && err == nil } // GetAllDenomMetaData retrieves all denominations metadata @@ -288,29 +247,14 @@ func (k BaseKeeper) GetAllDenomMetaData(ctx sdk.Context) []types.Metadata { // provides the metadata to a callback. If true is returned from the // callback, iteration is halted. func (k BaseKeeper) IterateAllDenomMetaData(ctx sdk.Context, cb func(types.Metadata) bool) { - store := ctx.KVStore(k.storeKey) - denomMetaDataStore := prefix.NewStore(store, types.DenomMetadataPrefix) - - iterator := denomMetaDataStore.Iterator(nil, nil) - defer sdk.LogDeferred(ctx.Logger(), func() error { return iterator.Close() }) - - for ; iterator.Valid(); iterator.Next() { - var metadata types.Metadata - k.cdc.MustUnmarshal(iterator.Value(), &metadata) - - if cb(metadata) { - break - } - } + _ = k.BaseViewKeeper.DenomMetadata.Walk(ctx, nil, func(_ string, metadata types.Metadata) bool { + return cb(metadata) + }) } // SetDenomMetaData sets the denominations metadata func (k BaseKeeper) SetDenomMetaData(ctx sdk.Context, denomMetaData types.Metadata) { - store := ctx.KVStore(k.storeKey) - denomMetaDataStore := prefix.NewStore(store, types.DenomMetadataPrefix) - - m := k.cdc.MustMarshal(&denomMetaData) - denomMetaDataStore.Set([]byte(denomMetaData.Base), m) + _ = k.BaseViewKeeper.DenomMetadata.Set(ctx, denomMetaData.Base, denomMetaData) } // SendCoinsFromModuleToAccount transfers coins from a ModuleAccount to an AccAddress. @@ -473,19 +417,11 @@ func (k BaseKeeper) BurnCoins(ctx sdk.Context, moduleName string, amounts sdk.Co // setSupply sets the supply for the given coin func (k BaseKeeper) setSupply(ctx sdk.Context, coin sdk.Coin) { - intBytes, err := coin.Amount.Marshal() - if err != nil { - panic(fmt.Errorf("unable to marshal amount value %v", err)) - } - - store := ctx.KVStore(k.storeKey) - supplyStore := prefix.NewStore(store, types.SupplyKey) - // Bank invariants and IBC requires to remove zero coins. if coin.IsZero() { - supplyStore.Delete(conv.UnsafeStrToBytes(coin.GetDenom())) + _ = k.Supply.Remove(ctx, coin.Denom) } else { - supplyStore.Set([]byte(coin.GetDenom()), intBytes) + _ = k.Supply.Set(ctx, coin.Denom, coin.Amount) } } @@ -527,26 +463,7 @@ func (k BaseKeeper) trackUndelegation(ctx sdk.Context, addr sdk.AccAddress, amt // with the balance of each coin. // The iteration stops if the callback returns true. func (k BaseViewKeeper) IterateTotalSupply(ctx sdk.Context, cb func(sdk.Coin) bool) { - store := ctx.KVStore(k.storeKey) - supplyStore := prefix.NewStore(store, types.SupplyKey) - - iterator := supplyStore.Iterator(nil, nil) - defer sdk.LogDeferred(ctx.Logger(), func() error { return iterator.Close() }) - - for ; iterator.Valid(); iterator.Next() { - var amount math.Int - err := amount.Unmarshal(iterator.Value()) - if err != nil { - panic(fmt.Errorf("unable to unmarshal supply value %v", err)) - } - - balance := sdk.Coin{ - Denom: string(iterator.Key()), - Amount: amount, - } - - if cb(balance) { - break - } - } + _ = k.Supply.Walk(ctx, nil, func(s string, m math.Int) bool { + return cb(sdk.NewCoin(s, m)) + }) } diff --git a/x/bank/keeper/send.go b/x/bank/keeper/send.go index c3cd5d0a28..5e49a66c17 100644 --- a/x/bank/keeper/send.go +++ b/x/bank/keeper/send.go @@ -3,8 +3,6 @@ package keeper import ( "fmt" - gogotypes "github.com/cosmos/gogoproto/types" - errorsmod "cosmossdk.io/errors" "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" @@ -92,20 +90,13 @@ func (k BaseSendKeeper) GetAuthority() string { // GetParams returns the total set of bank parameters. func (k BaseSendKeeper) GetParams(ctx sdk.Context) (params types.Params) { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.ParamsKey) - if bz == nil { - return params - } - - k.cdc.MustUnmarshal(bz, ¶ms) - return params + p, _ := k.Params.Get(ctx) + return p } // SetParams sets the total set of bank parameters. // // Note: params.SendEnabled is deprecated but it should be here regardless. - func (k BaseSendKeeper) SetParams(ctx sdk.Context, params types.Params) error { // Normally SendEnabled is deprecated but we still support it for backwards // compatibility. Using params.Validate() would fail due to the SendEnabled @@ -116,15 +107,7 @@ func (k BaseSendKeeper) SetParams(ctx sdk.Context, params types.Params) error { // override params without SendEnabled params = types.NewParams(params.DefaultSendEnabled) } - - store := ctx.KVStore(k.storeKey) - bz, err := k.cdc.Marshal(¶ms) - if err != nil { - return err - } - - store.Set(types.ParamsKey, bz) - return nil + return k.Params.Set(ctx, params) } // InputOutputCoins performs multi-send functionality. It accepts a series of @@ -374,11 +357,10 @@ func (k BaseSendKeeper) IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) e return nil } - store := ctx.KVStore(k.storeKey) defaultVal := k.GetParams(ctx).DefaultSendEnabled for _, coin := range coins { - if !k.getSendEnabledOrDefault(store, coin.Denom, defaultVal) { + if !k.getSendEnabledOrDefault(ctx, coin.Denom, defaultVal) { return types.ErrSendDisabled.Wrapf("%s transfers are currently disabled", coin.Denom) } } @@ -404,13 +386,13 @@ func (k BaseSendKeeper) GetBlockedAddresses() map[string]bool { // IsSendEnabledDenom returns the current SendEnabled status of the provided denom. func (k BaseSendKeeper) IsSendEnabledDenom(ctx sdk.Context, denom string) bool { - return k.getSendEnabledOrDefault(ctx.KVStore(k.storeKey), denom, k.GetParams(ctx).DefaultSendEnabled) + return k.getSendEnabledOrDefault(ctx, denom, k.GetParams(ctx).DefaultSendEnabled) } // GetSendEnabledEntry gets a SendEnabled entry for the given denom. // The second return argument is true iff a specific entry exists for the given denom. func (k BaseSendKeeper) GetSendEnabledEntry(ctx sdk.Context, denom string) (types.SendEnabled, bool) { - sendEnabled, found := k.getSendEnabled(ctx.KVStore(k.storeKey), denom) + sendEnabled, found := k.getSendEnabled(ctx, denom) if !found { return types.SendEnabled{}, false } @@ -420,57 +402,27 @@ func (k BaseSendKeeper) GetSendEnabledEntry(ctx sdk.Context, denom string) (type // SetSendEnabled sets the SendEnabled flag for a denom to the provided value. func (k BaseSendKeeper) SetSendEnabled(ctx sdk.Context, denom string, value bool) { - store := ctx.KVStore(k.storeKey) - k.setSendEnabledEntry(store, denom, value) + _ = k.SendEnabled.Set(ctx, denom, value) } // SetAllSendEnabled sets all the provided SendEnabled entries in the bank store. func (k BaseSendKeeper) SetAllSendEnabled(ctx sdk.Context, entries []*types.SendEnabled) { - store := ctx.KVStore(k.storeKey) for _, entry := range entries { - k.setSendEnabledEntry(store, entry.Denom, entry.Enabled) + _ = k.SendEnabled.Set(ctx, entry.Denom, entry.Enabled) } } -// setSendEnabledEntry sets SendEnabled for the given denom to the give value in the provided store. -func (k BaseSendKeeper) setSendEnabledEntry(store storetypes.KVStore, denom string, value bool) { - key := types.CreateSendEnabledKey(denom) - - bz := k.cdc.MustMarshal(&gogotypes.BoolValue{Value: value}) - store.Set(key, bz) -} - // DeleteSendEnabled deletes the SendEnabled flags for one or more denoms. // If a denom is provided that doesn't have a SendEnabled entry, it is ignored. func (k BaseSendKeeper) DeleteSendEnabled(ctx sdk.Context, denoms ...string) { - store := ctx.KVStore(k.storeKey) for _, denom := range denoms { - store.Delete(types.CreateSendEnabledKey(denom)) + _ = k.SendEnabled.Remove(ctx, denom) } } -// getSendEnabledPrefixStore gets a prefix store for the SendEnabled entries. -func (k BaseSendKeeper) getSendEnabledPrefixStore(ctx sdk.Context) storetypes.KVStore { - return prefix.NewStore(ctx.KVStore(k.storeKey), types.SendEnabledPrefix) -} - // IterateSendEnabledEntries iterates over all the SendEnabled entries. func (k BaseSendKeeper) IterateSendEnabledEntries(ctx sdk.Context, cb func(denom string, sendEnabled bool) bool) { - seStore := k.getSendEnabledPrefixStore(ctx) - - iterator := seStore.Iterator(nil, nil) - defer sdk.LogDeferred(ctx.Logger(), func() error { return iterator.Close() }) - - for ; iterator.Valid(); iterator.Next() { - denom := string(iterator.Key()) - - var enabled gogotypes.BoolValue - k.cdc.MustUnmarshal(iterator.Value(), &enabled) - - if cb(denom, enabled.Value) { - break - } - } + _ = k.SendEnabled.Walk(ctx, nil, cb) } // GetAllSendEnabledEntries gets all the SendEnabled entries that are stored. @@ -495,27 +447,24 @@ func (k BaseSendKeeper) GetAllSendEnabledEntries(ctx sdk.Context) []types.SendEn // if !found { // sendEnabled = DefaultSendEnabled // } -func (k BaseSendKeeper) getSendEnabled(store storetypes.KVStore, denom string) (bool, bool) { - key := types.CreateSendEnabledKey(denom) - if !store.Has(key) { +func (k BaseSendKeeper) getSendEnabled(ctx sdk.Context, denom string) (bool, bool) { + has, err := k.SendEnabled.Has(ctx, denom) + if err != nil || !has { return false, false } - bz := store.Get(key) - if bz == nil { + v, err := k.SendEnabled.Get(ctx, denom) + if err != nil { return false, false } - var enabled gogotypes.BoolValue - k.cdc.MustUnmarshal(bz, &enabled) - - return enabled.Value, true + return v, true } // getSendEnabledOrDefault gets the SendEnabled value for a denom. If it's not // in the store, this will return defaultVal. -func (k BaseSendKeeper) getSendEnabledOrDefault(store storetypes.KVStore, denom string, defaultVal bool) bool { - sendEnabled, found := k.getSendEnabled(store, denom) +func (k BaseSendKeeper) getSendEnabledOrDefault(ctx sdk.Context, denom string, defaultVal bool) bool { + sendEnabled, found := k.getSendEnabled(ctx, denom) if found { return sendEnabled } diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index 48d48d4291..8164b4824e 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -3,6 +3,10 @@ package keeper import ( "fmt" + "cosmossdk.io/collections" + + "github.com/cosmos/cosmos-sdk/runtime" + "cosmossdk.io/log" "cosmossdk.io/math" @@ -40,15 +44,33 @@ type BaseViewKeeper struct { cdc codec.BinaryCodec storeKey storetypes.StoreKey ak types.AccountKeeper + + Schema collections.Schema + Supply collections.Map[string, math.Int] + DenomMetadata collections.Map[string, types.Metadata] + SendEnabled collections.Map[string, bool] + Params collections.Item[types.Params] } // NewBaseViewKeeper returns a new BaseViewKeeper. func NewBaseViewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, ak types.AccountKeeper) BaseViewKeeper { - return BaseViewKeeper{ - cdc: cdc, - storeKey: storeKey, - ak: ak, + sb := collections.NewSchemaBuilder(runtime.NewKVStoreService(storeKey.(*storetypes.KVStoreKey))) + k := BaseViewKeeper{ + cdc: cdc, + storeKey: storeKey, + ak: ak, + Supply: collections.NewMap(sb, types.SupplyKey, "supply", collections.StringKey, sdk.IntValue), + DenomMetadata: collections.NewMap(sb, types.DenomMetadataPrefix, "denom_metadata", collections.StringKey, codec.CollValue[types.Metadata](cdc)), + SendEnabled: collections.NewMap(sb, types.SendEnabledPrefix, "send_enabled", collections.StringKey, codec.BoolValue), // NOTE: we use a bool value which uses protobuf to retain state backwards compat + Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), } + + schema, err := sb.Build() + if err != nil { + panic(err) + } + k.Schema = schema + return k } // Logger returns a module-specific logger. diff --git a/x/bank/types/keys.go b/x/bank/types/keys.go index a7ba7114d8..fbe24f19f3 100644 --- a/x/bank/types/keys.go +++ b/x/bank/types/keys.go @@ -1,6 +1,7 @@ package types import ( + "cosmossdk.io/collections" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/kv" @@ -15,15 +16,12 @@ const ( // RouterKey defines the module's message routing key RouterKey = ModuleName - - // ModuleQueryPath defines the ABCI query path of the module - ModuleQueryPath = "store/bank/key" ) // KVStore keys var ( - SupplyKey = []byte{0x00} - DenomMetadataPrefix = []byte{0x1} + SupplyKey = collections.NewPrefix(0) + DenomMetadataPrefix = collections.NewPrefix(1) DenomAddressPrefix = []byte{0x03} // BalancesPrefix is the prefix for the account balances store. We use a byte @@ -31,10 +29,10 @@ var ( BalancesPrefix = []byte{0x02} // SendEnabledPrefix is the prefix for the SendDisabled flags for a Denom. - SendEnabledPrefix = []byte{0x04} + SendEnabledPrefix = collections.NewPrefix(4) // ParamsKey is the prefix for x/bank parameters - ParamsKey = []byte{0x05} + ParamsKey = collections.NewPrefix(5) ) // AddressAndDenomFromBalancesStore returns an account address and denom from a balances prefix @@ -79,11 +77,3 @@ func CreateDenomAddressPrefix(denom string) []byte { copy(key[len(DenomAddressPrefix):], denom) return key } - -// CreateSendEnabledKey creates the key of the SendDisabled flag for a denom. -func CreateSendEnabledKey(denom string) []byte { - key := make([]byte, len(SendEnabledPrefix)+len(denom)) - copy(key, SendEnabledPrefix) - copy(key[len(SendEnabledPrefix):], denom) - return key -} diff --git a/x/bank/types/keys_test.go b/x/bank/types/keys_test.go index bfffdc2f62..ba0dd5c63e 100644 --- a/x/bank/types/keys_test.go +++ b/x/bank/types/keys_test.go @@ -68,12 +68,3 @@ func TestCreateDenomAddressPrefix(t *testing.T) { require.Len(key, len(types.DenomAddressPrefix)+4) require.Equal(append(types.DenomAddressPrefix, 'a', 'b', 'c', 0), key) } - -func TestCreateSendEnabledKey(t *testing.T) { - denom := "bazcoin" - expected := cloneAppend(types.SendEnabledPrefix, []byte(denom)) - actual := types.CreateSendEnabledKey(denom) - assert.Equal(t, expected, actual, "full byte slice") - assert.Equal(t, types.SendEnabledPrefix, actual[:len(types.SendEnabledPrefix)], "prefix") - assert.Equal(t, []byte(denom), actual[len(types.SendEnabledPrefix):], "denom part") -}