refactor(eigenState): extract generic ParseLogOutputAsType helper#520
refactor(eigenState): extract generic ParseLogOutputAsType helper#520pjdurden wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR centralizes JSON log output parsing into a reusable generic helper that preserves numeric precision (via json.Decoder.UseNumber()), and updates several event parsers to use it.
Changes:
- Added
base.ParseLogOutputAsType[T]for decodingOutputDataJSON into typed structs with precision-safe numeric handling. - Refactored multiple
stakerSharesevent output parsers to call the shared helper and simplify return paths. - Added unit tests covering successful decode, large-number precision preservation, and malformed JSON errors.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| pkg/eigenState/stakerShares/stakerShares.go | Replaces per-event JSON decoder boilerplate with the shared generic parsing helper. |
| pkg/eigenState/base/baseEigenState.go | Introduces ParseLogOutputAsType[T] using json.Decoder + UseNumber() for precision-safe decoding. |
| pkg/eigenState/base/baseEigenState_test.go | Adds tests validating typed decode, precision preservation, and error handling. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func ParseLogOutputAsType[T any](outputDataStr string) (*T, error) { | ||
| outputData := new(T) | ||
| decoder := json.NewDecoder(strings.NewReader(outputDataStr)) | ||
| decoder.UseNumber() | ||
| if err := decoder.Decode(outputData); err != nil { | ||
| return nil, err | ||
| } | ||
| return outputData, nil | ||
| } |
There was a problem hiding this comment.
done now. after the first decode the helper now does a second decoder.Decode(&struct{}{}) and requires io.EOF, so trailing or concatenated data is rejected instead of silently ignored. Added a unit test (rejects trailing data after the JSON value) covering it. Note the on-chain OutputData is always a single well-formed JSON value.
| // It decodes with a json.Decoder configured to UseNumber() so that large integer and decimal | ||
| // values (such as share amounts) retain their full precision. Without this, the standard | ||
| // decoder would parse them into a float64 and lose precision by representing them in | ||
| // scientific notation. Numeric fields on T that must preserve precision should therefore be | ||
| // typed as json.Number. |
There was a problem hiding this comment.
Reworded to attribute the precision loss to float64's 53-bit mantissa (integers above 2^53 can't be represented exactly and get silently rounded), rather than the misleading "scientific notation" framing.
3a73d20 to
cc5f709
Compare
The per-event parseLogOutputFor*Event helpers each repeated the same json.Decoder + UseNumber() boilerplate, differing only in the target struct type. This duplication appears across ~24 model files in the eigenState package. Introduce a generic base.ParseLogOutputAsType[T any] that performs the precision-preserving decode once, and migrate all seven call sites in the stakerShares model to use it. UseNumber() is retained so large share/slashing values keep full precision (json.Number) rather than being coerced to a lossy float64. The helper additionally rejects trailing or concatenated data after the JSON value (a strict superset of the previous behavior that no well-formed event output triggers). The remaining 23 model files can be migrated mechanically in follow-ups. Refs Layr-Labs#24 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cc5f709 to
535514c
Compare
|
Rebased onto latest master to clear the stale base. Hey @seanmcgary , @serichoi65 , it's ready for review whenever you've got time. |
Description
The per-event
parseLogOutputFor*Eventhelpers each repeated the samejson.Decoder+UseNumber()boilerplate, differing only in the target structtype — duplication that appears across ~24 model files in the eigenState package.
This introduces a generic
base.ParseLogOutputAsType[T any]that performs theprecision-preserving decode once, and migrates all seven call sites in the
stakerSharesmodel.UseNumber()is retained so large share/slashing valueskeep full precision (
json.Number) rather than being coerced to a lossyfloat64— behavior is unchanged. Scoped to one model file to stay reviewable;the remaining 23 model files are mechanical follow-ups.
Refs #24
Type of change
How Has This Been Tested?
baseEigenState_test.go): normal decode,large-integer precision round-trip (>2^53), and malformed-JSON error.
gofmt -l,go vet, andgo test ./pkg/eigenState/base/...all pass locally.Checklist