Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store Accessor Types #4554

mossid opened this issue Jun 14, 2019 · 0 comments


None yet
1 participant
Copy link

commented Jun 14, 2019

Store accessor types are the helpers for accessing the underlying KVStore. Currently, to get a value from a KVStore, you first need to:

  1. generate or get a store key
  2. get the value by using that key
  3. unmarshal the byte slice using the codec

This decreases the readability of the code and harder to review. The types suppress the steps to one. There are several types, mostly parameterized by the type of the stored value, but the generic pattern is shown at value.go


type Base struct {
  cdc *codec.Codec
  storefn func(sdk.Context) sdk.KVStore
  prefix []byte

Base is a pair of codec, store getter function, and prefix. cdc is used for marshaling/unmarshaling the interface{}s, storefn is used to get a KVStore given a Context, prefix will be applied as an argument for prefix.NewStore.


type Value struct {
  base Base
  key []byte

The Value contains cdc, key, storefn in it, so it is preparameterized with the key. It can be considered as a pointer to a specific location in the key-value state. For any operations on it, it will internally get the KVStore with the storefn(ctx), access the KVStore with the key, and marshal/unmarshal the value using the cdc.Must(Marshal/Unmarshal)BinaryBare.
Value is the generic type that handles all types, so it takes an interface{} as its value argument.

Variants of Value.

  • type Boolean: operations take bool instead of interface{} as its value
  • type Enum: operations take byte instead of interface{} as its value
  • type Integer: operations take uint64 instead of interface{} as its value

These variants are only differentiated by their type signature; the behaviours must be same with Value(all values must be marshaled/unmarshaled with the cdc).

The general pattern of methods:

  • Get(ctx sdk.Context, ptr interface{}): unmarshals the stored value to the pointer, noop if nil value, panic if cannot unmarshal
  • GetSafe(ctx sdk.Context, ptr interface{}) error: same with Get but returns error instead of panic
  • GetRaw(ctx sdk.Context) []byte: returns raw byte slice value
  • Set(ctx sdk.Context, o interface{}): sets the value into the state, panics if failed to marshal
  • SetRaw(ctx sdk.Context, bz []byte): sets the raw byte slice value into the state
  • Exists(ctx sdk.Context) bool: returns if the value exists
  • Delete(ctx sdk.Context): deletes the value
  • Key(ctx sdk.Context): returns the key that the value actually uses to access the KVStore

Only when the ctx is passed as an argument, we have a state access.


type Mapping struct {
  base Base

Mapping can be understood as a mapping from []byte to Value. It has a method Value(key []byte), which returns NewValue(Mapping.base, key). All the other methods have one more parameter key []byte, compared to Value, which is translated into Mapping.Value(key).{OperationName}.

Variants of Mapping:

  • type Indexer: operation takes uint64 instead of []byte as its key

@mossid mossid added the kvstore label Jun 14, 2019

@mossid mossid referenced a pull request that will close this issue Jun 14, 2019


R4R: Store Accessor Types #4514

1 of 5 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.