Skip to content

Commit

Permalink
ssz: add support for uint8 fields (#10)
Browse files Browse the repository at this point in the history
* Add support for uint8 en/decoding

* Apply suggestions from code review

* update readme
  • Loading branch information
gballet authored Jul 26, 2024
1 parent 3d1ff7a commit e1d852e
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ The table below is a summary of the methods available for `SizeSSZ` and `DefineS
| Type | Size API | Symmetric API | Asymmetric Encoding | Asymmetric Decoding | Asymmetric Hashing |
|:---------------------------:|:---------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------:|
| `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) |
| `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) |
Expand Down Expand Up @@ -587,4 +588,4 @@ BenchmarkMainnetState/beacon-state/208757379-bytes/encode-12 26
BenchmarkMainnetState/beacon-state/208757379-bytes/decode-12 27 40984980 ns/op 5093.51 MB/s 8456490 B/op 54910 allocs/op
BenchmarkMainnetState/beacon-state/208757379-bytes/merkleize-sequential-12 2 659472250 ns/op 316.55 MB/s 904 B/op 1 allocs/op
BenchmarkMainnetState/beacon-state/208757379-bytes/merkleize-concurrent-12 9 113414449 ns/op 1840.66 MB/s 16416 B/op 108 allocs/op
```
```
10 changes: 10 additions & 0 deletions cmd/sszgen/opset.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ func (p *parseContext) resolveBasicOpset(typ *types.Basic, tags *sizeTag) (opset
"DecodeBool({{.Codec}}, &{{.Field}})",
[]int{1},
}, nil
case types.Uint8:
if tags != nil && tags.size[0] != 1 {
return nil, fmt.Errorf("byte basic type requires ssz-size=1: have %d", tags.size[0])
}
return &opsetStatic{
"DefineUint8({{.Codec}}, &{{.Field}})",
"EncodeUint8({{.Codec}}, &{{.Field}})",
"DecodeUint8({{.Codec}}, &{{.Field}})",
[]int{1},
}, 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])
Expand Down
13 changes: 13 additions & 0 deletions codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ func DefineBool[T ~bool](c *Codec, v *T) {
HashBool(c.has, *v)
}

// DefineUint8 defines the next field as a uint8.
func DefineUint8[T ~uint8](c *Codec, n *T) {
if c.enc != nil {
EncodeUint8(c.enc, *n)
return
}
if c.dec != nil {
DecodeUint8(c.dec, n)
return
}
HashUint8(c.has, *n)
}

// DefineUint64 defines the next field as a uint64.
func DefineUint64[T ~uint64](c *Codec, n *T) {
if c.enc != nil {
Expand Down
19 changes: 19 additions & 0 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,25 @@ func DecodeBool[T ~bool](dec *Decoder, v *T) {
}
}

// DecodeUint8 parses a uint8.
func DecodeUint8[T ~uint8](dec *Decoder, n *T) {
if dec.err != nil {
return
}
if dec.inReader != nil {
_, dec.err = io.ReadFull(dec.inReader, dec.buf[:1])
*n = T(dec.buf[0])
dec.inRead += 1
} else {
if len(dec.inBuffer) < 1 {
dec.err = io.ErrUnexpectedEOF
return
}
*n = T(dec.inBuffer[0])
dec.inBuffer = dec.inBuffer[1:]
}
}

// DecodeUint64 parses a uint64.
func DecodeUint64[T ~uint64](dec *Decoder, n *T) {
if dec.err != nil {
Expand Down
14 changes: 14 additions & 0 deletions encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ func EncodeBool[T ~bool](enc *Encoder, v T) {
}
}

// EncodeUint8 serializes a uint8.
func EncodeUint8[T ~uint8](enc *Encoder, n T) {
if enc.outWriter != nil {
if enc.err != nil {
return
}
enc.buf[0] = byte(n)
_, enc.err = enc.outWriter.Write(enc.buf[:1])
} else {
enc.outBuffer[0] = byte(n)
enc.outBuffer = enc.outBuffer[1:]
}
}

// EncodeUint64 serializes a uint64.
func EncodeUint64[T ~uint64](enc *Encoder, n T) {
// Nope, dive into actual encoding
Expand Down
7 changes: 7 additions & 0 deletions hasher.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ func HashBool[T ~bool](h *Hasher, v T) {
}
}

// HashUint8 hashes a uint8.
func HashUint8[T ~uint8](h *Hasher, n T) {
var buffer [32]byte
buffer[0] = uint8(n)
h.insertChunk(buffer, 0)
}

// HashUint64 hashes a uint64.
func HashUint64[T ~uint64](h *Hasher, n T) {
var buffer [32]byte
Expand Down

0 comments on commit e1d852e

Please sign in to comment.