From 450df987748c4ecaba91a89d61f3f4e41e523f4c Mon Sep 17 00:00:00 2001 From: lavishq <96654752+Lavishq@users.noreply.github.com> Date: Fri, 26 Jul 2024 16:27:41 +0200 Subject: [PATCH 1/6] Add support for uint16 en/decoding --- README.md | 9 +++++---- cmd/sszgen/opset.go | 10 ++++++++++ codec.go | 13 +++++++++++++ decoder.go | 19 +++++++++++++++++++ encoder.go | 14 ++++++++++++++ hasher.go | 7 +++++++ 6 files changed, 68 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0805e8d..524c21c 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ Opposed to the static `Withdrawal` from the previous section, `ExecutionPayload` - First up, we will still need to know the static size of the object to avoid costly runtime calculations over and over. Just for reference, that would be the size of all the static fields in the object + 4 bytes for each dynamic field (offset encoding). Feel free to verify the number `512` above. - If the caller requested only the static size via the `fixed` parameter, return early. - If the caller, however, requested the total size of the object, we need to iterate over all the dynamic fields and accumulate all their sizes too. - - For all the usual Go suspects like slices and arrays of bytes; 2D sliced and arrays of bytes (i.e. `ExtraData` and `Transactions` above), there are helper methods available in the `ssz` package. + - For all the usual Go suspects like slices and arrays of bytes; 2D sliced and arrays of bytes (i.e. `ExtraData` and `Transactions` above), there are helper methods available in the `ssz` package. - For types implementing `ssz.StaticObject / ssz.DynamicObject` (e.g. one item of `Withdrawals` above), there are again helper methods available to use them as single objects, static array of objects, of dynamic slice of objects. The codec itself is very similar to the static example before: @@ -228,7 +228,7 @@ For types defined in perfect isolation - dedicated for SSZ - it's easy to define In reality, often you'll need to encode/decode types which already exist in a codebase, which might not map so cleanly onto the SSZ defined structure spec you want (e.g. you have one union type of `ExecutionPayload` that contains all the Bellatrix, Capella, Deneb, etc fork fields together) and you want to encode/decode them differently based on the context. -Most SSZ libraries will not permit you to do such a thing. Reflection based libraries *cannot* infer the context in which they should switch encoders and can neither can they represent multiple encodings at the same time. Generator based libraries again have no meaningful way to specify optional fields based on different constraints and contexts. +Most SSZ libraries will not permit you to do such a thing. Reflection based libraries *cannot* infer the context in which they should switch encoders and can neither can they represent multiple encodings at the same time. Generator based libraries again have no meaningful way to specify optional fields based on different constraints and contexts. The only way to handle such scenarios is to write the encoders by hand, and furthermore, encoding might be dependent on what's in the struct, whilst decoding might be dependent on what's it contained within. Completely asymmetric, so our unified *codec definition* approach from the previous sections cannot work. @@ -431,7 +431,7 @@ Points of interests to note: - The generator realized that this type contains dynamic fields (either through `ssz-max` tags or via embedded dynamic objects), so it generated an implementation for `ssz.DynamicObject` (vs. `ssz.StaticObject` in the previous section). - The generator took into consideration all the size `ssz-size` and `ssz-max` fields to generate serialization calls with different based types and runtime size checks. - - *Note, it is less performant to have runtime size checks like this, so if you know the size of a field, arrays are always preferable vs dynamic lists.* + - *Note, it is less performant to have runtime size checks like this, so if you know the size of a field, arrays are always preferable vs dynamic lists.* ### Cross-validated field sizes @@ -551,6 +551,7 @@ The table below is a summary of the methods available for `SizeSSZ` and `DefineS |:---------------------------:|:---------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------:| | `bool` | `1 byte` | [`DefineBool`](https://pkg.go.dev/github.com/karalabe/ssz#DefineBool) | [`EncodeBool`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeBool) | [`DecodeBool`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeBool) | [`HashBool`](https://pkg.go.dev/github.com/karalabe/ssz#HashBool) | | `uint8` | `1 bytes` | [`DefineUint8`](https://pkg.go.dev/github.com/karalabe/ssz#DefineUint8) | [`EncodeUint8`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeUint8) | [`DecodeUint8`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeUint8) | [`HashUint8`](https://pkg.go.dev/github.com/karalabe/ssz#HashUint8) | +| `uint16` | `2 bytes` | [`DefineUint16`](https://pkg.go.dev/github.com/karalabe/ssz#DefineUint16) | [`EncodeUint16`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeUint16) | [`DecodeUint16`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeUint16) | [`HashUint16`](https://pkg.go.dev/github.com/karalabe/ssz#HashUint16) | | `uint64` | `8 bytes` | [`DefineUint64`](https://pkg.go.dev/github.com/karalabe/ssz#DefineUint64) | [`EncodeUint64`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeUint64) | [`DecodeUint64`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeUint64) | [`HashUint64`](https://pkg.go.dev/github.com/karalabe/ssz#HashUint64) | | `[N]byte` as `bitvector[N]` | `N bytes` | [`DefineArrayOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#DefineArrayOfBits) | [`EncodeArrayOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeArrayOfBits) | [`DecodeArrayOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeArrayOfBits) | [`HashArrayOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#HashArrayOfBits) | | `bitfield.Bitlist`² | [`SizeSliceOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#SizeSliceOfBits) | [`DefineSliceOfBitsOffset`](https://pkg.go.dev/github.com/karalabe/ssz#DefineSliceOfBitsOffset) [`DefineSliceOfBitsContent`](https://pkg.go.dev/github.com/karalabe/ssz#DefineSliceOfBitsContent) | [`EncodeSliceOfBitsOffset`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeSliceOfBitsOffset) [`EncodeSliceOfBitsContent`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeSliceOfBitsContent) | [`DecodeSliceOfBitsOffset`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeSliceOfBitsOffset) [`DecodeSliceOfBitsContent`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeSliceOfBitsContent) | [`HashSliceOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#HashSliceOfBits) | @@ -582,7 +583,7 @@ The package includes a set of benchmarks for handling the beacon spec types and If you want to see the performance on a more realistic piece of data, you'll need to provide a beacon state SSZ object and place it into the project root named `state.ssz`. You can then run `go test --bench=Mainnet ./tests/manual_test.go` to explicitly run this one benchmark. A sample output running against a 208MB state export from around June 11, 2024, on a MacBook Pro M2 Max: ``` -go test --bench=Mainnet ./tests/manual_test.go +go test --bench=Mainnet ./tests/manual_test.go BenchmarkMainnetState/beacon-state/208757379-bytes/encode-12 26 45164494 ns/op 4622.16 MB/s 74 B/op 0 allocs/op BenchmarkMainnetState/beacon-state/208757379-bytes/decode-12 27 40984980 ns/op 5093.51 MB/s 8456490 B/op 54910 allocs/op diff --git a/cmd/sszgen/opset.go b/cmd/sszgen/opset.go index aee9139..27aa999 100644 --- a/cmd/sszgen/opset.go +++ b/cmd/sszgen/opset.go @@ -73,6 +73,16 @@ func (p *parseContext) resolveBasicOpset(typ *types.Basic, tags *sizeTag) (opset "DecodeUint8({{.Codec}}, &{{.Field}})", []int{1}, }, nil + case types.Uint16: + if tags != nil && tags.size[0] != 2 { + return nil, fmt.Errorf("byte basic type requires ssz-size=2: have %d", tags.size[0]) + } + return &opsetStatic{ + "DefineUint16({{.Codec}}, &{{.Field}})", + "EncodeUint16({{.Codec}}, &{{.Field}})", + "DecodeUint16({{.Codec}}, &{{.Field}})", + []int{2}, + }, nil case types.Uint64: if tags != nil && tags.size[0] != 8 { return nil, fmt.Errorf("uint64 basic type requires ssz-size=8: have %d", tags.size[0]) diff --git a/codec.go b/codec.go index 02fcae0..481d0b5 100644 --- a/codec.go +++ b/codec.go @@ -79,6 +79,19 @@ func DefineUint8[T ~uint8](c *Codec, n *T) { HashUint8(c.has, *n) } +// DefineUint16 defines the next field as a uint16. +func DefineUint16[T ~uint16](c *Codec, n *T) { + if c.enc != nil { + EncodeUint16(c.enc, *n) + return + } + if c.dec != nil { + DecodeUint16(c.dec, n) + return + } + HashUint16(c.has, *n) +} + // DefineUint64 defines the next field as a uint64. func DefineUint64[T ~uint64](c *Codec, n *T) { if c.enc != nil { diff --git a/decoder.go b/decoder.go index 0386a05..9e0b32b 100644 --- a/decoder.go +++ b/decoder.go @@ -128,6 +128,25 @@ func DecodeUint8[T ~uint8](dec *Decoder, n *T) { } } +// DecodeUint16 parses a uint16. +func DecodeUint16[T ~uint16](dec *Decoder, n *T) { + if dec.err != nil { + return + } + if dec.inReader != nil { + _, dec.err = io.ReadFull(dec.inReader, dec.buf[:2]) + *n = T(binary.LittleEndian.Uint16(dec.buf[:2])) + dec.inRead += 2 + } else { + if len(dec.inBuffer) < 2 { + dec.err = io.ErrUnexpectedEOF + return + } + *n = T(binary.LittleEndian.Uint16(dec.inBuffer)) + dec.inBuffer = dec.inBuffer[2:] + } +} + // DecodeUint64 parses a uint64. func DecodeUint64[T ~uint64](dec *Decoder, n *T) { if dec.err != nil { diff --git a/encoder.go b/encoder.go index ff48eea..8ea42ed 100644 --- a/encoder.go +++ b/encoder.go @@ -113,6 +113,20 @@ func EncodeUint8[T ~uint8](enc *Encoder, n T) { } } +// EncodeUint16 serializes a uint16. +func EncodeUint16[T ~uint16](enc *Encoder, n T) { + if enc.outWriter != nil { + if enc.err != nil { + return + } + binary.LittleEndian.PutUint16(enc.buf[:2], (uint16)(n)) + _, enc.err = enc.outWriter.Write(enc.buf[:2]) + } else { + binary.LittleEndian.PutUint16(enc.outBuffer, (uint16)(n)) + enc.outBuffer = enc.outBuffer[2:] + } +} + // EncodeUint64 serializes a uint64. func EncodeUint64[T ~uint64](enc *Encoder, n T) { // Nope, dive into actual encoding diff --git a/hasher.go b/hasher.go index 945fdab..f946398 100644 --- a/hasher.go +++ b/hasher.go @@ -80,6 +80,13 @@ func HashUint8[T ~uint8](h *Hasher, n T) { h.insertChunk(buffer, 0) } +// HashUint16 hashes a uint16. +func HashUint16[T ~uint16](h *Hasher, n T) { + var buffer [32]byte + binary.LittleEndian.PutUint16(buffer[:], uint16(n)) + h.insertChunk(buffer, 0) +} + // HashUint64 hashes a uint64. func HashUint64[T ~uint64](h *Hasher, n T) { var buffer [32]byte From ca92f0fa8ef62415f64b5de31cd1ce636b5d3d78 Mon Sep 17 00:00:00 2001 From: lavishq <96654752+Lavishq@users.noreply.github.com> Date: Fri, 26 Jul 2024 16:34:10 +0200 Subject: [PATCH 2/6] Add support for uint32 en/decoding --- README.md | 1 + cmd/sszgen/opset.go | 10 ++++++++++ codec.go | 13 +++++++++++++ decoder.go | 19 +++++++++++++++++++ encoder.go | 14 ++++++++++++++ hasher.go | 7 +++++++ 6 files changed, 64 insertions(+) diff --git a/README.md b/README.md index 524c21c..7175a16 100644 --- a/README.md +++ b/README.md @@ -552,6 +552,7 @@ The table below is a summary of the methods available for `SizeSSZ` and `DefineS | `bool` | `1 byte` | [`DefineBool`](https://pkg.go.dev/github.com/karalabe/ssz#DefineBool) | [`EncodeBool`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeBool) | [`DecodeBool`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeBool) | [`HashBool`](https://pkg.go.dev/github.com/karalabe/ssz#HashBool) | | `uint8` | `1 bytes` | [`DefineUint8`](https://pkg.go.dev/github.com/karalabe/ssz#DefineUint8) | [`EncodeUint8`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeUint8) | [`DecodeUint8`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeUint8) | [`HashUint8`](https://pkg.go.dev/github.com/karalabe/ssz#HashUint8) | | `uint16` | `2 bytes` | [`DefineUint16`](https://pkg.go.dev/github.com/karalabe/ssz#DefineUint16) | [`EncodeUint16`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeUint16) | [`DecodeUint16`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeUint16) | [`HashUint16`](https://pkg.go.dev/github.com/karalabe/ssz#HashUint16) | +| `uint32` | `4 bytes` | [`DefineUint32`](https://pkg.go.dev/github.com/karalabe/ssz#DefineUint32) | [`EncodeUint32`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeUint32) | [`DecodeUint32`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeUint32) | [`HashUint32`](https://pkg.go.dev/github.com/karalabe/ssz#HashUint32) | | `uint64` | `8 bytes` | [`DefineUint64`](https://pkg.go.dev/github.com/karalabe/ssz#DefineUint64) | [`EncodeUint64`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeUint64) | [`DecodeUint64`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeUint64) | [`HashUint64`](https://pkg.go.dev/github.com/karalabe/ssz#HashUint64) | | `[N]byte` as `bitvector[N]` | `N bytes` | [`DefineArrayOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#DefineArrayOfBits) | [`EncodeArrayOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeArrayOfBits) | [`DecodeArrayOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeArrayOfBits) | [`HashArrayOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#HashArrayOfBits) | | `bitfield.Bitlist`² | [`SizeSliceOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#SizeSliceOfBits) | [`DefineSliceOfBitsOffset`](https://pkg.go.dev/github.com/karalabe/ssz#DefineSliceOfBitsOffset) [`DefineSliceOfBitsContent`](https://pkg.go.dev/github.com/karalabe/ssz#DefineSliceOfBitsContent) | [`EncodeSliceOfBitsOffset`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeSliceOfBitsOffset) [`EncodeSliceOfBitsContent`](https://pkg.go.dev/github.com/karalabe/ssz#EncodeSliceOfBitsContent) | [`DecodeSliceOfBitsOffset`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeSliceOfBitsOffset) [`DecodeSliceOfBitsContent`](https://pkg.go.dev/github.com/karalabe/ssz#DecodeSliceOfBitsContent) | [`HashSliceOfBits`](https://pkg.go.dev/github.com/karalabe/ssz#HashSliceOfBits) | diff --git a/cmd/sszgen/opset.go b/cmd/sszgen/opset.go index 27aa999..eb0aeca 100644 --- a/cmd/sszgen/opset.go +++ b/cmd/sszgen/opset.go @@ -83,6 +83,16 @@ func (p *parseContext) resolveBasicOpset(typ *types.Basic, tags *sizeTag) (opset "DecodeUint16({{.Codec}}, &{{.Field}})", []int{2}, }, nil + case types.Uint32: + if tags != nil && tags.size[0] != 4 { + return nil, fmt.Errorf("byte basic type requires ssz-size=4: have %d", tags.size[0]) + } + return &opsetStatic{ + "DefineUint32({{.Codec}}, &{{.Field}})", + "EncodeUint32({{.Codec}}, &{{.Field}})", + "DecodeUint32({{.Codec}}, &{{.Field}})", + []int{4}, + }, nil case types.Uint64: if tags != nil && tags.size[0] != 8 { return nil, fmt.Errorf("uint64 basic type requires ssz-size=8: have %d", tags.size[0]) diff --git a/codec.go b/codec.go index 481d0b5..3b36736 100644 --- a/codec.go +++ b/codec.go @@ -92,6 +92,19 @@ func DefineUint16[T ~uint16](c *Codec, n *T) { HashUint16(c.has, *n) } +// DefineUint16 defines the next field as a uint16. +func DefineUint32[T ~uint32](c *Codec, n *T) { + if c.enc != nil { + EncodeUint32(c.enc, *n) + return + } + if c.dec != nil { + DecodeUint32(c.dec, n) + return + } + HashUint32(c.has, *n) +} + // DefineUint64 defines the next field as a uint64. func DefineUint64[T ~uint64](c *Codec, n *T) { if c.enc != nil { diff --git a/decoder.go b/decoder.go index 9e0b32b..26f469d 100644 --- a/decoder.go +++ b/decoder.go @@ -147,6 +147,25 @@ func DecodeUint16[T ~uint16](dec *Decoder, n *T) { } } +// DecodeUint32 parses a uint32. +func DecodeUint32[T ~uint32](dec *Decoder, n *T) { + if dec.err != nil { + return + } + if dec.inReader != nil { + _, dec.err = io.ReadFull(dec.inReader, dec.buf[:4]) + *n = T(binary.LittleEndian.Uint32(dec.buf[:4])) + dec.inRead += 4 + } else { + if len(dec.inBuffer) < 4 { + dec.err = io.ErrUnexpectedEOF + return + } + *n = T(binary.LittleEndian.Uint32(dec.inBuffer)) + dec.inBuffer = dec.inBuffer[4:] + } +} + // DecodeUint64 parses a uint64. func DecodeUint64[T ~uint64](dec *Decoder, n *T) { if dec.err != nil { diff --git a/encoder.go b/encoder.go index 8ea42ed..2f262e1 100644 --- a/encoder.go +++ b/encoder.go @@ -127,6 +127,20 @@ func EncodeUint16[T ~uint16](enc *Encoder, n T) { } } +// EncodeUint32 serializes a uint32. +func EncodeUint32[T ~uint32](enc *Encoder, n T) { + if enc.outWriter != nil { + if enc.err != nil { + return + } + binary.LittleEndian.PutUint32(enc.buf[:4], (uint32)(n)) + _, enc.err = enc.outWriter.Write(enc.buf[:4]) + } else { + binary.LittleEndian.PutUint32(enc.outBuffer, (uint32)(n)) + enc.outBuffer = enc.outBuffer[4:] + } +} + // EncodeUint64 serializes a uint64. func EncodeUint64[T ~uint64](enc *Encoder, n T) { // Nope, dive into actual encoding diff --git a/hasher.go b/hasher.go index f946398..51fb530 100644 --- a/hasher.go +++ b/hasher.go @@ -87,6 +87,13 @@ func HashUint16[T ~uint16](h *Hasher, n T) { h.insertChunk(buffer, 0) } +// HashUint32 hashes a uint32. +func HashUint32[T ~uint32](h *Hasher, n T) { + var buffer [32]byte + binary.LittleEndian.PutUint32(buffer[:], uint32(n)) + h.insertChunk(buffer, 0) +} + // HashUint64 hashes a uint64. func HashUint64[T ~uint64](h *Hasher, n T) { var buffer [32]byte From 0561bc156fa6396abde50745b2814fa7315c899f Mon Sep 17 00:00:00 2001 From: lavishq Date: Fri, 26 Jul 2024 21:28:47 +0200 Subject: [PATCH 3/6] added test for VarTestStruct && ComplexTestStruct --- tests/consensus_specs_test.go | 2 ++ .../gen_fixed_test_struct_ssz.go | 17 +++++++++++++++++ .../gen_small_test_struct_ssz.go | 16 ++++++++++++++++ .../consensus-spec-tests/types_basics.go | 13 +++++++++++++ 4 files changed, 48 insertions(+) create mode 100644 tests/testtypes/consensus-spec-tests/gen_fixed_test_struct_ssz.go create mode 100644 tests/testtypes/consensus-spec-tests/gen_small_test_struct_ssz.go diff --git a/tests/consensus_specs_test.go b/tests/consensus_specs_test.go index ab584f2..c3c1570 100644 --- a/tests/consensus_specs_test.go +++ b/tests/consensus_specs_test.go @@ -49,6 +49,8 @@ func commonPrefix(a []byte, b []byte) []byte { // consensus spec tests repo and runs the encoding/decoding/hashing round. func TestConsensusSpecBasics(t *testing.T) { testConsensusSpecBasicType[*types.SingleFieldTestStruct](t, "SingleFieldTestStruct") + testConsensusSpecBasicType[*types.SingleFieldTestStruct](t, "SmallTestStruct") + testConsensusSpecBasicType[*types.SingleFieldTestStruct](t, "FixedTestStruct") testConsensusSpecBasicType[*types.BitsStruct](t, "BitsStruct") } diff --git a/tests/testtypes/consensus-spec-tests/gen_fixed_test_struct_ssz.go b/tests/testtypes/consensus-spec-tests/gen_fixed_test_struct_ssz.go new file mode 100644 index 0000000..1cdf576 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_fixed_test_struct_ssz.go @@ -0,0 +1,17 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// SizeSSZ returns the total size of the static ssz object. +func (obj *FixedTestStruct) SizeSSZ() uint32 { + return 1 + 1 + 1 +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *FixedTestStruct) DefineSSZ(codec *ssz.Codec) { + ssz.DefineArrayOfBits(codec, &obj.A, 1) // Field (0) - A - 1 bytes + ssz.DefineArrayOfBits(codec, &obj.B, 8) // Field (1) - B - 1 bytes + ssz.DefineArrayOfBits(codec, &obj.C, 4) // Field (2) - C - 1 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/gen_small_test_struct_ssz.go b/tests/testtypes/consensus-spec-tests/gen_small_test_struct_ssz.go new file mode 100644 index 0000000..bdb18e7 --- /dev/null +++ b/tests/testtypes/consensus-spec-tests/gen_small_test_struct_ssz.go @@ -0,0 +1,16 @@ +// Code generated by github.com/karalabe/ssz. DO NOT EDIT. + +package consensus_spec_tests + +import "github.com/karalabe/ssz" + +// SizeSSZ returns the total size of the static ssz object. +func (obj *SmallTestStruct) SizeSSZ() uint32 { + return 1 + 1 +} + +// DefineSSZ defines how an object is encoded/decoded. +func (obj *SmallTestStruct) DefineSSZ(codec *ssz.Codec) { + ssz.DefineArrayOfBits(codec, &obj.A, 2) // Field (0) - A - 1 bytes + ssz.DefineArrayOfBits(codec, &obj.B, 2) // Field (1) - B - 1 bytes +} diff --git a/tests/testtypes/consensus-spec-tests/types_basics.go b/tests/testtypes/consensus-spec-tests/types_basics.go index f7dfc4f..8f7c984 100644 --- a/tests/testtypes/consensus-spec-tests/types_basics.go +++ b/tests/testtypes/consensus-spec-tests/types_basics.go @@ -7,12 +7,25 @@ package consensus_spec_tests import "github.com/prysmaticlabs/go-bitfield" //go:generate go run -cover ../../../cmd/sszgen -type SingleFieldTestStruct -out gen_single_field_test_struct_ssz.go +//go:generate go run -cover ../../../cmd/sszgen -type SmallTestStruct -out gen_small_test_struct_ssz.go +//go:generate go run -cover ../../../cmd/sszgen -type FixedTestStruct -out gen_fixed_test_struct_ssz.go //go:generate go run -cover ../../../cmd/sszgen -type BitsStruct -out gen_bits_struct_ssz.go type SingleFieldTestStruct struct { A byte } +type SmallTestStruct struct { + A uint16 + B uint16 +} + +type FixedTestStruct struct { + A uint8 + B uint64 + C uint32 +} + type BitsStruct struct { A bitfield.Bitlist `ssz-max:"5"` B [1]byte `ssz-size:"2" ssz:"bits"` From c9a7608d831ff5fbbdc33a09b921fd858aacb130 Mon Sep 17 00:00:00 2001 From: lavishq Date: Fri, 26 Jul 2024 21:43:45 +0200 Subject: [PATCH 4/6] fix test types --- tests/consensus_specs_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/consensus_specs_test.go b/tests/consensus_specs_test.go index c3c1570..95fe40c 100644 --- a/tests/consensus_specs_test.go +++ b/tests/consensus_specs_test.go @@ -49,8 +49,8 @@ func commonPrefix(a []byte, b []byte) []byte { // consensus spec tests repo and runs the encoding/decoding/hashing round. func TestConsensusSpecBasics(t *testing.T) { testConsensusSpecBasicType[*types.SingleFieldTestStruct](t, "SingleFieldTestStruct") - testConsensusSpecBasicType[*types.SingleFieldTestStruct](t, "SmallTestStruct") - testConsensusSpecBasicType[*types.SingleFieldTestStruct](t, "FixedTestStruct") + testConsensusSpecBasicType[*types.SmallTestStruct](t, "SmallTestStruct") + testConsensusSpecBasicType[*types.FixedTestStruct](t, "FixedTestStruct") testConsensusSpecBasicType[*types.BitsStruct](t, "BitsStruct") } From cfe3a0061577d119410a072c82d4baa50889456b Mon Sep 17 00:00:00 2001 From: lavishq Date: Fri, 26 Jul 2024 21:53:59 +0200 Subject: [PATCH 5/6] fixed comment and print typos --- cmd/sszgen/opset.go | 4 ++-- codec.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/sszgen/opset.go b/cmd/sszgen/opset.go index eb0aeca..27f8470 100644 --- a/cmd/sszgen/opset.go +++ b/cmd/sszgen/opset.go @@ -75,7 +75,7 @@ func (p *parseContext) resolveBasicOpset(typ *types.Basic, tags *sizeTag) (opset }, nil case types.Uint16: if tags != nil && tags.size[0] != 2 { - return nil, fmt.Errorf("byte basic type requires ssz-size=2: have %d", tags.size[0]) + return nil, fmt.Errorf("uint16 basic type requires ssz-size=2: have %d", tags.size[0]) } return &opsetStatic{ "DefineUint16({{.Codec}}, &{{.Field}})", @@ -85,7 +85,7 @@ func (p *parseContext) resolveBasicOpset(typ *types.Basic, tags *sizeTag) (opset }, nil case types.Uint32: if tags != nil && tags.size[0] != 4 { - return nil, fmt.Errorf("byte basic type requires ssz-size=4: have %d", tags.size[0]) + return nil, fmt.Errorf("uint32 basic type requires ssz-size=4: have %d", tags.size[0]) } return &opsetStatic{ "DefineUint32({{.Codec}}, &{{.Field}})", diff --git a/codec.go b/codec.go index 3b36736..061e9a0 100644 --- a/codec.go +++ b/codec.go @@ -92,7 +92,7 @@ func DefineUint16[T ~uint16](c *Codec, n *T) { HashUint16(c.has, *n) } -// DefineUint16 defines the next field as a uint16. +// DefineUint32 defines the next field as a uint32. func DefineUint32[T ~uint32](c *Codec, n *T) { if c.enc != nil { EncodeUint32(c.enc, *n) From ba211b53492bbaefaa1cfbf02704d7f88cdce29d Mon Sep 17 00:00:00 2001 From: lavishq Date: Fri, 26 Jul 2024 22:09:40 +0200 Subject: [PATCH 6/6] regenerating concensus-spec-tests --- .../consensus-spec-tests/gen_fixed_test_struct_ssz.go | 8 ++++---- .../consensus-spec-tests/gen_small_test_struct_ssz.go | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/testtypes/consensus-spec-tests/gen_fixed_test_struct_ssz.go b/tests/testtypes/consensus-spec-tests/gen_fixed_test_struct_ssz.go index 1cdf576..cfebc25 100644 --- a/tests/testtypes/consensus-spec-tests/gen_fixed_test_struct_ssz.go +++ b/tests/testtypes/consensus-spec-tests/gen_fixed_test_struct_ssz.go @@ -6,12 +6,12 @@ import "github.com/karalabe/ssz" // SizeSSZ returns the total size of the static ssz object. func (obj *FixedTestStruct) SizeSSZ() uint32 { - return 1 + 1 + 1 + return 1 + 8 + 4 } // DefineSSZ defines how an object is encoded/decoded. func (obj *FixedTestStruct) DefineSSZ(codec *ssz.Codec) { - ssz.DefineArrayOfBits(codec, &obj.A, 1) // Field (0) - A - 1 bytes - ssz.DefineArrayOfBits(codec, &obj.B, 8) // Field (1) - B - 1 bytes - ssz.DefineArrayOfBits(codec, &obj.C, 4) // Field (2) - C - 1 bytes + ssz.DefineUint8(codec, &obj.A) // Field (0) - A - 1 bytes + ssz.DefineUint64(codec, &obj.B) // Field (1) - B - 8 bytes + ssz.DefineUint32(codec, &obj.C) // Field (2) - C - 4 bytes } diff --git a/tests/testtypes/consensus-spec-tests/gen_small_test_struct_ssz.go b/tests/testtypes/consensus-spec-tests/gen_small_test_struct_ssz.go index bdb18e7..020e433 100644 --- a/tests/testtypes/consensus-spec-tests/gen_small_test_struct_ssz.go +++ b/tests/testtypes/consensus-spec-tests/gen_small_test_struct_ssz.go @@ -6,11 +6,11 @@ import "github.com/karalabe/ssz" // SizeSSZ returns the total size of the static ssz object. func (obj *SmallTestStruct) SizeSSZ() uint32 { - return 1 + 1 + return 2 + 2 } // DefineSSZ defines how an object is encoded/decoded. func (obj *SmallTestStruct) DefineSSZ(codec *ssz.Codec) { - ssz.DefineArrayOfBits(codec, &obj.A, 2) // Field (0) - A - 1 bytes - ssz.DefineArrayOfBits(codec, &obj.B, 2) // Field (1) - B - 1 bytes + ssz.DefineUint16(codec, &obj.A) // Field (0) - A - 2 bytes + ssz.DefineUint16(codec, &obj.B) // Field (1) - B - 2 bytes }