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

R4R: Store Accessor Types #4514

Closed
wants to merge 43 commits into from
Closed

R4R: Store Accessor Types #4514

wants to merge 43 commits into from

Conversation

mossid
Copy link
Contributor

@mossid mossid commented Jun 7, 2019

closes: #4554


  • Targeted PR against correct branch (see CONTRIBUTING.md)

  • Linked to github-issue with discussion and accepted design OR link to spec that describes this work.

  • Wrote tests

  • Updated relevant documentation (docs/)

  • Added a relevant changelog entry: clog add [section] [stanza] [message]

  • rereviewed Files changed in the github PR explorer


For Admin Use:

  • Added appropriate labels to PR (ex. wip, ready-for-review, docs)
  • Reviewers Assigned
  • Squashed all commits, uses message "Merge pull request #XYZ: [title]" (coding standards)

@codecov
Copy link

codecov bot commented Jun 11, 2019

Codecov Report

Merging #4514 into master will increase coverage by 0.02%.
The diff coverage is 59.93%.

@@            Coverage Diff            @@
##           master   #4514      +/-   ##
=========================================
+ Coverage   54.98%     55%   +0.02%     
=========================================
  Files         297     305       +8     
  Lines       18225   18514     +289     
=========================================
+ Hits        10021   10184     +163     
- Misses       7466    7581     +115     
- Partials      738     749      +11

@mossid mossid changed the title WIP: Store Accessor Types R4R: Store Accessor Types Jun 11, 2019
@mossid mossid marked this pull request as ready for review June 11, 2019 22:36
@alexanderbez
Copy link
Contributor

@mossid before starting a review, can you quickly open an issue outline the rationale and ideas behind this PR and why it's warranted please? Also, address the merge conflicts (but this isn't necessary pre-review) 👍

store/state/base.go Outdated Show resolved Hide resolved
store/state/enum.go Outdated Show resolved Hide resolved
store/state/test_common.go Outdated Show resolved Hide resolved
store/state/test_common.go Outdated Show resolved Hide resolved
store/state/test_common.go Outdated Show resolved Hide resolved
store/state/test_common.go Outdated Show resolved Hide resolved
store/state/test_common.go Outdated Show resolved Hide resolved
store/state/mapping.go Outdated Show resolved Hide resolved
@fedekunze
Copy link
Collaborator

@mossid what's the status of this PR? do you need someone to help out with what's left?

Copy link
Contributor

@alexanderbez alexanderbez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mossid -- performed an initial review. One thing to note is I'd like to see unit tests testing all the behavior of both the generic and types accessors. In addition, I'm not sure if store/state is the best structure...maybe store/accessor?

store/state/base.go Outdated Show resolved Hide resolved
store/state/boolean.go Show resolved Hide resolved
store/state/enum.go Show resolved Hide resolved
store/state/indexer.go Show resolved Hide resolved
store/state/integer.go Show resolved Hide resolved
store/state/value.go Show resolved Hide resolved
return v.base.store(ctx)
}

func (v Value) Cdc() *codec.Codec {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need a getter for the codec? What if we passed in the codec instead of having it as part of Value?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updates on this suggestion @mossid ?

Copy link
Contributor Author

@mossid mossid Sep 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having codec as an argument will make the code bit harder to read but okay with it, will change

return v.base.key(v.key)
}

type GetSafeErrorType byte
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets move this to a separate errors.go file

func NewMapping(base Base, prefix []byte) Mapping {
return Mapping{
base: base.Prefix(prefix),
start: []byte{}, // preventing nil key access in store.Last
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment really has no context.

store/state/mapping.go Show resolved Hide resolved
Copy link
Contributor

@alexanderbez alexanderbez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mossid there seems to be some remaining feedback to be addressed. Also, what are your thoughts in the package being store/accessor instead of store/state? The latter is a bit ambiguous.

m.Value(key).Delete(ctx)
}

func (m Mapping) Cdc() *codec.Codec {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump @mossid


type KVStore = sdk.KVStore
type Context = sdk.Context
type CLIContext = context.CLIContext
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bump @mossid

Value
}

func (v Value) Boolean() Boolean {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these functions should be moved to value.go

func (v Value) Type() Type {

return
}

func (v Enum) Transit(ctx Context, from, to byte) bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the name either

}

// GetSafeError is error type for GetSafe method
type GetSafeError struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type GetSafeError struct {
type SafeError struct {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't understand why we need an error wrapper type like this one. What happens if GetSafe just returns an error? Why do we want to wrap it? All those answers should be specified on a comment here

)

// GetSafeErrorType is enum for indicating the type of error
type GetSafeErrorType byte
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type GetSafeErrorType byte
type SafeErrorType byte

// GetSafeError is error type for GetSafe method
type GetSafeError struct {
ty GetSafeErrorType
inner error
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
inner error
err error

store/state/integer.go Outdated Show resolved Hide resolved
store/state/mapping.go Outdated Show resolved Hide resolved
store/state/value.go Outdated Show resolved Hide resolved
store/state/value.go Outdated Show resolved Hide resolved
var testkey = sdk.NewKVStoreKey("test")

func init() {
// register
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

@fedekunze
Copy link
Collaborator

@alexanderbez I noticed there are a bunch of changes to the store accessors on the upstream PRs. I think the best would be to fork #5057 and remove everything that's not related to the accessors.

}

return q.store.Query(req), nil

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary trailing newline (from whitespace)

// proof if TrustNode is disabled. If proof verification fails or the query
// height is invalid, an error will be returned.
func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) {
func (ctx CLIContext) queryABCI(req abci.RequestQuery) (resp abci.ResponseQuery, err error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary leading newline (from whitespace)

return reflect.ValueOf(ptr).Elem().Interface()
}

func TestTypeValue(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function 'TestTypeValue' is too long (66 > 60) (from funlen)

}

err = ctx.verifyProof(path, resp)
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naked return in func queryABCI with 44 lines of code (from nakedret)

}

func (v integerT) Unmarshal(bz []byte, ptr interface{}) {
res, err := DecodeInt(bz, v.enc)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v.enc undefined (type integerT has no field or method enc) (from typecheck)

}

func (v valueT) Unmarshal(bz []byte, ptr interface{}) {
v.m.cdc.MustUnmarshalBinaryBare(bz, ptr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v.m undefined (type valueT has no field or method m) (from typecheck)

}

func (v Value) QueryRaw(q ABCIQuerier) ([]byte, *Proof, error) {
resp, err := q.Query(v.m.StoreName(), v.KeyBytes())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v.m undefined (type Value has no field or method m) (from typecheck)

// NewValue constructs a Value.
func NewValue(m Mapping, key []byte) Value {
return Value{
m: m,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unknown field m in struct literal (from typecheck)

res = 0
return
}
res, err = DecodeInt(value, v.enc)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v.enc undefined (type Integer has no field or method enc) (from typecheck)

// Prefix returns a new Indexer with the updated prefix
func (ix Indexer) Prefix(prefix []byte) Indexer {
return Indexer{
m: ix.m.Prefix(prefix),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ix.m undefined (type Indexer has no field or method m) (from typecheck)

return Indexer{
m: ix.m.Prefix(prefix),

enc: ix.enc,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ix.enc undefined (type Indexer has no field or method enc) (from typecheck)

Copy link
Collaborator

@fedekunze fedekunze left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a lot of questions regarding the design decisions of this PR

// Mapping is key []byte -> value []byte mapping using a base(possibly prefixed).
// All store accessing operations are redirected to the Value corresponding to
// the key argument.
type Mapping struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: these are the basic fields used on a Keeper

return Mapping{
storeKey: m.storeKey,
cdc: m.cdc,
prefix: join(m.prefix, prefix),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name is misleading, it should just replace the mapping's prefix to another one

req := abci.RequestQuery{
Path: "/store/" + storeName + "/key",
Data: key,
Prove: true,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this hardcoded to true?


var _ ABCIQuerier = CLIQuerier{}

type CLIQuerier struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we shouldn't declare all these types. It is really confusing as to what is the difference between the current sdk.Querier and these ones. The new CLI flow is extremely confusing and intruduces a lot of overhead because of the new accessor types. This will significantly diminish the current dev UX on creating modules.

What are the significant benefits of using/declaring these types? There's no documentation on the process of integrating the accessors.

We should integrate the new accessor types to the current system with Queriers or directly calling them from the cliContext


func (q CLIQuerier) Query(storeName string, key []byte) (abci.ResponseQuery, error) {
req := abci.RequestQuery{
Path: "/store/" + storeName + "/key",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these prefixes and suffixes are not intuitive at all

req := abci.RequestQuery{
Path: "/" + storeName + "/key",
Data: key,
Prove: true,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also hardcoded, why?

return v.m.KeyBytes(v.key)
}

func (v Value) QueryRaw(q ABCIQuerier) ([]byte, *Proof, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here you are passing a Querier as a parameter to a function from Value when ideally it should be the other way. This makes things really confusing and forces you to define all the query logic on the client/cli/query .go itself because you need to define cliCtx there.

return resp.Value, resp.Proof, nil
}

func (v Value) Query(q ABCIQuerier, ptr interface{}) (*Proof, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

// Value is a capability for reading and writing on a specific key-value point
// in the state. Value consists of a mapping and a key. An actor holding a Value
// has a full access right on that state point.
type Value struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so the Value is part of a KVStore.... but the Value itself has a map "key []byte -> value []byte" and a prefix? This is all super confusing...

Also, why does the value contain the one of the keys of the map?


// KeyBytes returns the prefixed key that the Value is providing to the KVStore.
func (v Value) KeyBytes() []byte {
return v.m.KeyBytes(v.key)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the only instance that the Value.key is used. Why do you need to declare it on the type and not pass it as an argument?

This is telling me that Value itself is really a KVPair with the capability to retrieve the actual value from the defined Value.Mapping, it's not really a value, making the name of the type misleadding.

@jackzampolin
Copy link
Member

It sounds like this feature has been shelved after further review. I vote that we close this implementation PR.

@fedekunze fedekunze deleted the joon/store-mapping branch December 24, 2019 16:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Store Accessor Types
5 participants