-
Notifications
You must be signed in to change notification settings - Fork 17
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
Add UnmarshallValidateMsg to generated functions #25
Conversation
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 comparison algorithm looks OK. I'd like to see a test here or in go-algorand. (upd: found a test in go-algorand)
My main concerns are:
- allowing
UnmarshalValidateMsg
without giving the less function silently disables the feature. - performance penalty with additional branches for types not required validating. Need to benchmark to ensure if they are negligible.
u.p.printf("\n return %s.unmarshalMsg(bts, false)", c) | ||
u.p.printf("\n}") | ||
|
||
u.p.printf("\nfunc (%s %s) UnmarshalValidateMsg(bts []byte) (o []byte, err error) {", c, methodRecv) |
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.
add a code that errs if LessFunction not set for this type?
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.
LessFunction missing is a compile time issue not runtime. Should I just emit a panic inside the code if LessFn is expected and missing?
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.
Ah I see yeah I can just return a nil slice and error since I already have error interface.
u.p.printf("\nfor %s > 0 {", sz) | ||
u.p.printf("\nvar %s %s; var %s %s; %s--", m.Keyidx, m.Key.TypeName(), m.Validx, m.Value.TypeName(), sz) | ||
next(u, m.Key) | ||
if m.Key.LessFunction() != "" { |
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.
maybe do not require less func for all types? since numbers, strings, arrays are comparable, byte slices can be generated with bytes.Compare if m.Key.TypeName() == []bytes - i.e. to make this feature more usable by requiring less work by a user.
Btw, it looks like I can call UnmarshalValidateMsg on a type without providing LessFunction, this code would not be generated and I might get no err even there is an ordering issue.
I guess we need to go one of the roads:
- allow
UnmarshalValidateMsg
only for types withLessFunction
provided. - have
UnmarshalValidateMsg
to generate own code by propagatingvalidate=true/false
flag down in generator methods:UnmarshalMsg
would generate regular stuff as now withoutif validate
overhead, andUnmarshalValidateMsg
would generate code withif validate
+ err if less function not provided but needed.
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.
maybe do not require less func for all types? since numbers, strings, arrays are comparable, byte slices can be generated with bytes.Compare if m.Key.TypeName() == []bytes - i.e. to make this feature more usable by requiring less work by a user.
I agree -- I can make it smarter
I guess we need to go one of the roads:
- allow
UnmarshalValidateMsg
only for types withLessFunction
provided.- have
UnmarshalValidateMsg
to generate own code by propagatingvalidate=true/false
flag down in generator methods:UnmarshalMsg
would generate regular stuff as now withoutif validate
overhead, andUnmarshalValidateMsg
would generate code withif validate
+ err if less function not provided but needed.
These two don't seem mutually exclusive to me. The first one is a correctness issue and the second seems like a performance concern.
I could fix the issue by including the if validate
statement as separate and then inside that block do another if check if we have the LessFn and return an error uncoditionally if LessFn is missing.
Co-authored-by: Pavel Zbitskiy <[email protected]>
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.
My main concern is still correctness/robustness of the code. If LessFunction not set then calling calling UnmarshalValidateMsg
could return OK because the entire branch if m.Key.LessFunction()
and if validate
was not generated.
If validate should now be generated regardless of whether LessFn is set and error is hardcoded for cases when lessFn is not available. Do you see a case where I missed it? |
How? the code is still there and I can't see preconditions like if m.Key.LessFunction() != "" {
u.p.printf("\nif validate && %s && %s(%s, %s) {", lastSet, m.Key.LessFunction(), m.Keyidx, last)
u.p.printf("\nerr = &msgp.ErrNonCanonical{}")
u.p.printf("\nreturn")
u.p.printf("\n}")
} |
Apologies, I had pushed the branch to upstream as well since I needed access to msgp.Uint64Less functions for code in Re: not being to merge do you mean the go-algorand branch? Yeah it's due to other files getting msgp changes, I was going to do it once I have a go-ahead on the approach/perf tradeoffs since I will need to change the go.mod and autogen checker versions anyway |
Summary
Existing UnmarshallMsg will currently decode any valid messagepack message that corresponds to a given type. For on-chain things such as Transactions and Certs.
This PR generates an additional method called UnmarshallValidateMsg that fails if:
It changes the interface for the
msgp:sort
directive adding LessFn as the last argument which defines a method of comparing two map fields.Generated code example is in accompanying PR in go-algorand repo: algorand/go-algorand#5605
Testing
Perhaps add explicit tests in repo confirming that canonicity is correctly tested