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

Closed
mossid opened this issue Jun 14, 2019 · 3 comments
Closed

Store Accessor Types #4554

mossid opened this issue Jun 14, 2019 · 3 comments
Assignees
Labels
C:Store S:proposed T: Dev UX UX for SDK developers (i.e. how to call our code)

Comments

@mossid
Copy link
Contributor

mossid 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

Base

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.

Value

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.

Mapping

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
@alexanderbez
Copy link
Contributor

@mossid thanks for creating this issue as a reference to the existing PR. From what I understand, this exists mainly as an improvement to developer ergonomics -- it doesn't not provide any discrete new functionality. A "nice-to-have" if you will.

However, @jackzampolin stated that this is somehow needed for IBC? Can you elaborate on that please? What does this allow you to do that you cannot currently do for IBC?

@alexanderbez alexanderbez added S:proposed T: Dev UX UX for SDK developers (i.e. how to call our code) labels Jul 22, 2019
@tnachen tnachen added this to the v0.38.0 milestone Aug 22, 2019
@mossid
Copy link
Contributor Author

mossid commented Sep 5, 2019

Working ADR on #4998

@alexanderbez alexanderbez modified the milestones: v0.38.0, IBC Implementation & Integration Oct 1, 2019
@fedekunze fedekunze removed this from the IBC Implementation & Integration milestone Oct 15, 2019
@fedekunze
Copy link
Collaborator

Closing this as it was not included on the SDK at the end. A new proposal with a more detailed ADR would be required to include it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C:Store S:proposed T: Dev UX UX for SDK developers (i.e. how to call our code)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants