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

Add UnmarshallValidateMsg to generated functions #25

Merged
merged 10 commits into from
Aug 11, 2023

Conversation

iansuvak
Copy link
Contributor

@iansuvak iansuvak commented Jul 24, 2023

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:

  • A sort inversion is detected for either a struct field name or a map key
  • A struct is encoded as an array instead of map.

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

@iansuvak iansuvak changed the title WIP: Add UnmarshallValidateMsg to generated functions Add UnmarshallValidateMsg to generated functions Jul 24, 2023
@iansuvak iansuvak self-assigned this Jul 25, 2023
@iansuvak iansuvak added Team Carbon-11 Work belongs to Carbon-11 enhancement New feature or request labels Jul 25, 2023
@jsgranados jsgranados added the p2p Work related to the p2p project label Aug 3, 2023
Copy link
Contributor

@algorandskiy algorandskiy left a 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)
Copy link
Contributor

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?

Copy link
Contributor Author

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?

Copy link
Contributor Author

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.

gen/unmarshal.go Outdated Show resolved Hide resolved
gen/unmarshal.go Show resolved Hide resolved
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() != "" {
Copy link
Contributor

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:

  1. allow UnmarshalValidateMsg only for types with LessFunction provided.
  2. have UnmarshalValidateMsg to generate own code by propagating validate=true/false flag down in generator methods: UnmarshalMsg would generate regular stuff as now without if validate overhead, and UnmarshalValidateMsg would generate code with if validate + err if less function not provided but needed.

Copy link
Contributor Author

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:

  1. allow UnmarshalValidateMsg only for types with LessFunction provided.
  2. have UnmarshalValidateMsg to generate own code by propagating validate=true/false flag down in generator methods: UnmarshalMsg would generate regular stuff as now without if validate overhead, and UnmarshalValidateMsg would generate code with if 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]>
Copy link
Contributor

@algorandskiy algorandskiy left a 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.

@iansuvak
Copy link
Contributor Author

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?

@algorandskiy
Copy link
Contributor

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 validate and not LessFunction then error. Maybe it was not pushed? Btw, GH says "This branch cannot be rebased due to conflicts".

	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}")
	}

@iansuvak
Copy link
Contributor Author

How? the code is still there and I can't see preconditions like if validate and not LessFunction then error. Maybe it was not pushed? Btw, GH says "This branch cannot be rebased due to conflicts".

Apologies, I had pushed the branch to upstream as well since I needed access to msgp.Uint64Less functions for code in go-algorand repo to compile but didn't push to this one which the PR is based off of. Fixed now.

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

@iansuvak iansuvak merged commit 3fbccb2 into algorand:master Aug 11, 2023
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request p2p Work related to the p2p project Team Carbon-11 Work belongs to Carbon-11
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants