refactor(bank): use collections for state management (#15293)

Co-authored-by: testinginprod <testinginprod@somewhere.idk>
This commit is contained in:
testinginprod 2023-03-09 12:36:39 +01:00 committed by GitHub
parent 138e0e1d3c
commit 2b7a1102ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 159 additions and 255 deletions

View File

@ -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

View File

@ -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)
})
}

4
go.mod
View File

@ -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

8
go.sum
View File

@ -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=

View File

@ -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
}

View File

@ -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

View File

@ -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=

View File

@ -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

View File

@ -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=

View File

@ -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 {

View File

@ -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

View File

@ -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))
})
}

View File

@ -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, &params)
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(&params)
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
}

View File

@ -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.

View File

@ -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
}

View File

@ -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")
}