cosmos-sdk/x/params/store/store.go

188 lines
4.9 KiB
Go
Raw Normal View History

2018-09-18 04:16:20 -07:00
package store
import (
"fmt"
"reflect"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
)
2018-10-06 06:50:58 -07:00
// Additional capicity to be allocated for Store.space
// So we don't have to allocate extra space each time appending to the key
const extraKeyCap = 20
// Individual parameter store for each keeper
2018-09-27 11:12:52 -07:00
// Transient store persists for a block, so we use it for
// recording whether the parameter has been changed or not
2018-09-18 04:16:20 -07:00
type Store struct {
cdc *codec.Codec
2018-09-27 11:12:52 -07:00
key sdk.StoreKey // []byte -> []byte, stores parameter
tkey sdk.StoreKey // []byte -> bool, stores parameter change
2018-09-18 10:16:51 -07:00
space []byte
}
2018-09-18 04:16:20 -07:00
// NewStore constructs a store with namestore
2018-10-06 06:50:58 -07:00
func NewStore(cdc *codec.Codec, key sdk.StoreKey, tkey sdk.StoreKey, space string) (res Store) {
res = Store{
cdc: cdc,
key: key,
tkey: tkey,
}
2018-10-06 06:50:58 -07:00
spacebz := []byte(space)
res.space = make([]byte, len(spacebz), len(spacebz)+extraKeyCap)
copy(res.space, spacebz)
return
}
2018-10-06 06:50:58 -07:00
// Returns a KVStore identical with ctx.KVStore(s.key).Prefix()
2018-09-18 10:16:51 -07:00
func (s Store) kvStore(ctx sdk.Context) sdk.KVStore {
2018-10-06 06:50:58 -07:00
// append here is safe, appends within a function won't cause
// weird side effects when its singlethreaded
2018-09-18 10:22:42 -07:00
return ctx.KVStore(s.key).Prefix(append(s.space, '/'))
2018-09-18 10:16:51 -07:00
}
// Returns a KVStore identical with ctx.TransientStore(s.tkey).Prefix()
func (s Store) transientStore(ctx sdk.Context) sdk.KVStore {
2018-10-06 06:50:58 -07:00
// append here is safe, appends within a function won't cause
// weird side effects when its singlethreaded
2018-09-18 10:22:42 -07:00
return ctx.TransientStore(s.tkey).Prefix(append(s.space, '/'))
2018-09-18 10:16:51 -07:00
}
// Get parameter from store
2018-09-27 11:52:29 -07:00
func (s Store) Get(ctx sdk.Context, key []byte, ptr interface{}) {
2018-09-18 10:16:51 -07:00
store := s.kvStore(ctx)
2018-09-27 11:52:29 -07:00
bz := store.Get(key)
err := s.cdc.UnmarshalJSON(bz, ptr)
if err != nil {
panic(err)
}
}
// GetIfExists do not modify ptr if the stored parameter is nil
2018-09-27 11:52:29 -07:00
func (s Store) GetIfExists(ctx sdk.Context, key []byte, ptr interface{}) {
2018-09-18 10:16:51 -07:00
store := s.kvStore(ctx)
2018-09-27 11:52:29 -07:00
bz := store.Get(key)
if bz == nil {
return
}
err := s.cdc.UnmarshalJSON(bz, ptr)
if err != nil {
panic(err)
}
}
// Get raw bytes of parameter from store
2018-09-27 11:52:29 -07:00
func (s Store) GetRaw(ctx sdk.Context, key []byte) []byte {
2018-09-18 10:16:51 -07:00
store := s.kvStore(ctx)
2018-09-27 11:52:29 -07:00
res := store.Get(key)
return res
}
// Check if the parameter is set in the store
2018-09-27 11:52:29 -07:00
func (s Store) Has(ctx sdk.Context, key []byte) bool {
2018-09-18 10:16:51 -07:00
store := s.kvStore(ctx)
2018-09-27 11:52:29 -07:00
return store.Has(key)
}
// Returns true if the parameter is set in the block
2018-09-27 11:52:29 -07:00
func (s Store) Modified(ctx sdk.Context, key []byte) bool {
2018-09-18 10:16:51 -07:00
tstore := s.transientStore(ctx)
2018-09-27 11:52:29 -07:00
return tstore.Has(key)
}
// Set parameter, return error if stored parameter has different type from input
2018-09-26 11:30:57 -07:00
// Also set to the transient store to record change
2018-09-27 11:52:29 -07:00
func (s Store) Set(ctx sdk.Context, key []byte, param interface{}) {
2018-09-18 10:16:51 -07:00
store := s.kvStore(ctx)
2018-09-27 11:52:29 -07:00
bz := store.Get(key)
2018-09-26 11:30:57 -07:00
// To prevent invalid parameter set, we check the type of the stored parameter
// and try to match it with the provided parameter. It continues only if they matches.
// It is possible because parameter set happens rarely.
if bz != nil {
2018-09-26 11:30:57 -07:00
ptrType := reflect.PtrTo(reflect.TypeOf(param))
ptr := reflect.New(ptrType).Interface()
if s.cdc.UnmarshalJSON(bz, ptr) != nil {
2018-09-10 05:10:06 -07:00
panic(fmt.Errorf("Type mismatch with stored param and provided param"))
}
}
bz, err := s.cdc.MarshalJSON(param)
if err != nil {
2018-09-10 05:10:06 -07:00
panic(err)
}
2018-09-27 11:52:29 -07:00
store.Set(key, bz)
2018-09-18 10:16:51 -07:00
tstore := s.transientStore(ctx)
2018-09-27 11:52:29 -07:00
tstore.Set(key, []byte{})
}
// Set raw bytes of parameter
2018-09-26 11:30:57 -07:00
// Also set to the transient store to record change
2018-09-27 11:52:29 -07:00
func (s Store) SetRaw(ctx sdk.Context, key []byte, param []byte) {
2018-09-18 10:16:51 -07:00
store := s.kvStore(ctx)
2018-09-27 11:52:29 -07:00
store.Set(key, param)
2018-09-18 10:16:51 -07:00
tstore := s.transientStore(ctx)
2018-09-27 11:52:29 -07:00
tstore.Set(key, []byte{})
}
2018-09-18 09:27:54 -07:00
// Get to ParamStruct
func (s Store) GetStruct(ctx sdk.Context, ps ParamStruct) {
2018-10-06 06:50:58 -07:00
for _, pair := range ps.KeyValuePairs() {
2018-09-18 09:27:54 -07:00
s.Get(ctx, pair.Key, pair.Field)
}
}
2018-09-17 08:28:13 -07:00
// Set from ParamStruct
2018-09-18 09:27:54 -07:00
func (s Store) SetStruct(ctx sdk.Context, ps ParamStruct) {
2018-10-06 06:50:58 -07:00
for _, pair := range ps.KeyValuePairs() {
2018-09-18 10:16:51 -07:00
// pair.Field is a pointer to the field, so indirecting the ptr.
// go-amino automatically handles it but just for sure,
// since SetStruct is meant to be used in InitGenesis
// so this method will not be called frequently
v := reflect.Indirect(reflect.ValueOf(pair.Field)).Interface()
s.Set(ctx, pair.Key, v)
2018-09-17 08:28:13 -07:00
}
}
2018-09-18 10:16:51 -07:00
// Returns internal namespace
func (s Store) Space() string {
return string(s.space)
}
2018-09-18 04:16:20 -07:00
// Wrapper of Store, provides immutable functions only
type ReadOnlyStore struct {
s Store
}
// Exposes Get
2018-09-27 11:52:29 -07:00
func (ros ReadOnlyStore) Get(ctx sdk.Context, key []byte, ptr interface{}) {
ros.s.Get(ctx, key, ptr)
}
// Exposes GetRaw
2018-09-27 11:52:29 -07:00
func (ros ReadOnlyStore) GetRaw(ctx sdk.Context, key []byte) []byte {
return ros.s.GetRaw(ctx, key)
}
// Exposes Has
2018-09-27 11:52:29 -07:00
func (ros ReadOnlyStore) Has(ctx sdk.Context, key []byte) bool {
return ros.s.Has(ctx, key)
}
// Exposes Modified
2018-09-27 11:52:29 -07:00
func (ros ReadOnlyStore) Modified(ctx sdk.Context, key []byte) bool {
return ros.s.Modified(ctx, key)
}
2018-09-18 10:16:51 -07:00
// Exposes Space
func (ros ReadOnlyStore) Space() string {
return ros.s.Space()
}