-
Notifications
You must be signed in to change notification settings - Fork 2
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
feat(params): UnmarshalChainJSONConfig
and MarshalChainJSONConfig
#92
base: main
Are you sure you want to change the base?
Conversation
32afb0b
to
a41a78d
Compare
params/json.libevm_test.go
Outdated
@@ -144,3 +145,60 @@ func TestChainConfigJSONRoundTrip(t *testing.T) { | |||
}) | |||
} | |||
} | |||
|
|||
func Test_UnmarshalChainConfig(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.
Please only include _
in identifiers when it's required by a general convention; the only instance I can think of off the top of my head is the godoc
parsing of testable examples.
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 _
right after Test
can be removed indeed. However, if we test for example func (o *Object) myFunc()
naming the test as TestObject_myFunc
is better than TestObjectmyFunc
readability-wise, would you agree or have another suggestion? 🤔
params/json.libevm_test.go
Outdated
@@ -144,3 +145,60 @@ func TestChainConfigJSONRoundTrip(t *testing.T) { | |||
}) | |||
} | |||
} | |||
|
|||
func Test_UnmarshalChainConfig(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.
I suspect that the existing test cases will be sufficient if you refactor as I recommended above. That will also give us a greater degree of confidence between the situations where extras are explicitly registered vs merely passed to the function.
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.
They are for the happy path for both the marshal and unmarshal functions. However, I prefer to have unit tests for each marshal and umarshal functions, on top of the existing test, to test unhappy paths/corner cases, especially given the any
/generic thingies which are prone to error.
…raNotRegistered` and `unmarshalChainConfigJSONExtraRegistered`
06c7610
to
a6ebb69
Compare
a6ebb69
to
a46252d
Compare
params/json.libevm.go
Outdated
switch { | ||
case err != nil: | ||
return fmt.Errorf("decoding root chain config: %s", err) | ||
case extra == nil: // ignore the extra, whether at the root JSON depth, or at the "extra" JSON field. |
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.
do we want to support this case where the user pass in a nil
extra? 🤔 Or not really? Thinking about the case an extra
set to nil is passed and we silently not decode the extra content
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 changed to return an error extra pointer argument is nil
because:
- I don't think there is a point using this function at all if the extra argument is a (typed) nil
- Discarding silently the extra field sounds like a dangerous path, better to return an 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.
No, we don't want to support nil extras because that is never a valid use case. In the extras-registered scenario it will never be nil (by design), and in the non-registered scenario the caller should just use the regular JSON decoding mechanism of either json.Decode([]byte, *ChainConfig)
or ChainConfig.UnmarshalJSON()
.
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.
Yes I think returning an error in case the extra is nil makes sense in that case then.
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.
nice, let's add MarshalJSON, we can do it in this or a separate PR
params/json.libevm_test.go
Outdated
|
||
testCases := map[string]struct { | ||
jsonData string // string for convenience | ||
extra any |
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.
nit: seems this is always set to &testExtra{}
so we can remove it from the table struct and have the test instantiate it.
or if it is to keep things generic, there could be newExtra: func() any { return &testExtra{} }
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 changed it a bit to be extra any
to be able to throw different things at it.
params/json.libevm.go
Outdated
return json.Unmarshal(data, (*chainConfigWithoutMethods)(c)) | ||
} | ||
extraConstructors := registeredExtras.Get() |
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.
(style) Please don't use such verbose variable names when the scope is only 3 lines; they distract from reading of the code. I'd personally be happy with just r
, but understand that others are not—as long as it's not 5 syllables.
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've read a few style guides including that one, my view on it, unless it's a really obvious use (i.e. i
for a range index), it's nice to have a meaningful name almost always. For example c
instead of extraConstructors
made me wonder what was c
and had to lookup where it was created and what .Get()
was returning, and, because it's a generic function, had to dig into extraConstructors struct
. Not a big deal obviously, but it does make readability worst in my opinion.
Obviously that's my opinion on this, so I'll conform to the existing code and use shorter variable names 😉
EDIT: also one more reason is I do like to use a single letter for the receiving struct for methods, so using single letter variables in there makes things confusing imo
EDIT2: my brain is kind of very formed (malformed or ok-formed, debatable 😄) to use explicit non-single-letter variable names, so feel free to hammer with style comments in case you feel like it should be a smaller variable name. I got the extraConstructors
-> ec
but after going through the rest of the code I wrote, I'm feeling like:
params/json.libevm.go
Outdated
switch { | ||
case err != nil: | ||
return fmt.Errorf("decoding root chain config: %s", err) | ||
case extra == nil: // ignore the extra, whether at the root JSON depth, or at the "extra" JSON field. |
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.
No, we don't want to support nil extras because that is never a valid use case. In the extras-registered scenario it will never be nil (by design), and in the non-registered scenario the caller should just use the regular JSON decoding mechanism of either json.Decode([]byte, *ChainConfig)
or ChainConfig.UnmarshalJSON()
.
case extra == nil: // ignore the extra, whether at the root JSON depth, or at the "extra" JSON field. | ||
case reuseJSONRoot: | ||
err = json.Unmarshal(data, extra) | ||
if err != 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.
(style) When a variable is scoped to a block, please scope it as such where possible, e.g. by initialisation within a if
or switch
statement.
if err := json.Unmarshal(...); err != 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.
In my opinion, the short if forms makes it harder to read, but maybe that's just me eyes acting strange 😄
Regarding the scoping, we could change this to
err := json.Unmarshal(data, extra)
if err != nil {
? 🤔
params/json.libevm.go
Outdated
// `data` is decoded into `config` and the extra is ignored. | ||
func UnmarshalChainConfigJSON[T any](data []byte, config *ChainConfig, extra *T, reuseJSONRoot bool) (err error) { | ||
err = json.Unmarshal(data, (*chainConfigWithoutMethods)(config)) | ||
switch { |
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 a switch needed? Either we are reusing the JSON root or we're not, and each of those may or may not return an error.
See my comment below about double unmarshalling into the extra
field when not reusing the root, which may have influenced this.
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 double unmarshaling is fixed, and switch converted to 2 ifs which are indeed perhaps clearer 😉
require.NoError(t, json.Unmarshal([]byte(tt.jsonInput), got)) | ||
require.Equal(t, tt.want, got) | ||
}) | ||
expectedEncoded := bytes.NewBuffer(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.
Why is this change to the original test 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.
I was just going over the existing test, and was wondering why we had subtests where it seems to me this makes it more convoluted? Maybe I missed something though. I can revert it of course, no worry.
params/json.libevm_test.go
Outdated
"invalid_json": { | ||
extra: &testExtra{}, | ||
expectedExtra: &testExtra{}, | ||
errMessage: "decoding root chain config: unexpected end of JSON input", |
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 a change-detector test, which results in having to change tests when implementations change.
See: https://google.github.io/styleguide/go/decisions#test-error-semantics
If you want to confirm precise error-spawning pathways then please either compare against a set of error variables (probably most appropriate here as along as they're not exported) or, in more complex situations, with specific error types.
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.
Indeed, I'm aware 😄 I do test error messages, since I have seen many error messages that were unclear and/or repeating themselves, and I found testing error strings do reduce a lot of this from happening.
I don't think testing error variables (except nil vs non nil) help really, especially since we are focusing on "human readable" and not programmatically handled errors - we don't wrap errors with %w
. But I can change this to check for nil vs non-nil only.
} | ||
} | ||
|
||
func TestUnmarshalChainConfigJSON(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.
- What cases aren't covered by the original tests? (Other than errors, that is)
- Can the non-erroring cases just be added to the table above?
Re (1); while coverage isn't a perfect metric, I'm seeing full happy-path coverage on your branch with just the originals.
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.
See #92 (comment) 😉
params/json.libevm_test.go
Outdated
jsonData string // string for convenience | ||
extra *testExtra | ||
reuseJSONRoot bool | ||
expectedConfig ChainConfig |
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 rest of libevm
uses "want" instead of "expected" and "got" instead of "actual".
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.
Changed expected
prefixes to want
prefixes.
However - ha I want shorter variable names perhaps - regarding actual
(and got
), I think i.e. data, ok := MarshalXYZ
in a test is better than actualData, actualOk := MarshalXYZ
and there is no need for an actual prefix really? And if it's only one variable being checked, why not name it to what it actually is i.e. data
instead of actual
da45de2
to
2172aa7
Compare
UnmarshalChainConfig
functionUnmarshalChainJSONConfig
and MarshalChainJSONConfig
Why this should be merged
Allow wallet and other clients to parse blocks from both coreth & subnet-evm, and also make their genesis/chain-configs.
How this works
🕐 Waiting on feedback from Arr4n to make sure this is how it's supposed to operate before updating the function comment and associated test(s)
UnmarshalChainConfig
is a standalone functionfunc UnmarshalChainConfigJSON[T any](data []byte, config *ChainConfig, extra *T) (err error)
taking as input arguments:data []byte
the json data to decodeconfig *ChainConfig
the chain config pointer to decode to, except the json"extra"
key, if non-nilextra *T
the extra destination pointer to decode the"extra"
key object to, if non-nilHow this was tested
New unit test
Test_UnmarshalChainConfig