-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Conversation
Codecov Report
@@ 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 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) 👍 |
@mossid what's the status of this PR? do you need someone to help out with what's left? |
There was a problem hiding this 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/value.go
Outdated
return v.base.store(ctx) | ||
} | ||
|
||
func (v Value) Cdc() *codec.Codec { |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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
store/state/value.go
Outdated
return v.base.key(v.key) | ||
} | ||
|
||
type GetSafeErrorType byte |
There was a problem hiding this comment.
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
store/state/mapping.go
Outdated
func NewMapping(base Base, prefix []byte) Mapping { | ||
return Mapping{ | ||
base: base.Prefix(prefix), | ||
start: []byte{}, // preventing nil key access in store.Last |
There was a problem hiding this comment.
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.
There was a problem hiding this 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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump @mossid
store/state/types.go
Outdated
|
||
type KVStore = sdk.KVStore | ||
type Context = sdk.Context | ||
type CLIContext = context.CLIContext |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bump @mossid
f52abaf
to
04543f8
Compare
Co-Authored-By: Federico Kunze <[email protected]>
…o joon/store-mapping
Value | ||
} | ||
|
||
func (v Value) Boolean() Boolean { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type GetSafeError struct { | |
type SafeError struct { |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type GetSafeErrorType byte | |
type SafeErrorType byte |
// GetSafeError is error type for GetSafe method | ||
type GetSafeError struct { | ||
ty GetSafeErrorType | ||
inner error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inner error | |
err error |
var testkey = sdk.NewKVStoreKey("test") | ||
|
||
func init() { | ||
// register |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
@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. |
* Store accessor upstream changes (#5119)
} | ||
|
||
return q.store.Query(req), nil | ||
|
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
)
Co-Authored-By: Federico Kunze <[email protected]>
} | ||
|
||
func (v integerT) Unmarshal(bz []byte, ptr interface{}) { | ||
res, err := DecodeInt(bz, v.enc) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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()) |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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), |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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
)
There was a problem hiding this 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 { |
There was a problem hiding this comment.
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), |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
It sounds like this feature has been shelved after further review. I vote that we close this implementation PR. |
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 explorerFor Admin Use: