From fc22678edd605a51ecee4ec602937e51a24a361d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 24 Feb 2023 14:10:23 +0200 Subject: [PATCH 1/8] uint256: implement fastssz marshaling interfaces --- conversion.go | 56 +++++++-- conversion_test.go | 302 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 349 insertions(+), 9 deletions(-) diff --git a/conversion.go b/conversion.go index 6a234411..56744d04 100644 --- a/conversion.go +++ b/conversion.go @@ -465,6 +465,46 @@ func bigEndianUint56(b []byte) uint64 { uint64(b[2])<<32 | uint64(b[1])<<40 | uint64(b[0])<<48 } +// MarshalSSZTo implements the fastssz.Marshaler interface and serializes the +// integer into an already pre-allocated buffer. +func (z *Int) MarshalSSZTo(dst []byte) ([]byte, error) { + if len(dst) != 32 { + return nil, fmt.Errorf("%w: have %d, want %d bytes", ErrBadBufferLength, len(dst), 32) + } + binary.LittleEndian.PutUint64(dst[0:8], z[0]) + binary.LittleEndian.PutUint64(dst[8:16], z[1]) + binary.LittleEndian.PutUint64(dst[16:24], z[2]) + binary.LittleEndian.PutUint64(dst[24:32], z[3]) + + return dst, nil +} + +// MarshalSSZ implements the fastssz.Marshaler interface and returns the integer +// marshalled into a newly allocated byte slice. +func (z *Int) MarshalSSZ() ([]byte, error) { + return z.MarshalSSZTo(make([]byte, 32)) +} + +// SizeSSZ implements the fastssz.Marshaler interface and returns the byte size +// of the 256 bit int. +func (z *Int) SizeSSZ() int { + return 32 +} + +// UnmarshalSSZ implements the fastssz.Unmarshaler interface and parses an encoded +// integer into the local struct. +func (z *Int) UnmarshalSSZ(buf []byte) error { + if len(buf) != 32 { + return fmt.Errorf("%w: have %d, want %d bytes", ErrBadEncodedLength, len(buf), 32) + } + z[0] = binary.LittleEndian.Uint64(buf[0:8]) + z[1] = binary.LittleEndian.Uint64(buf[8:16]) + z[2] = binary.LittleEndian.Uint64(buf[16:24]) + z[3] = binary.LittleEndian.Uint64(buf[24:32]) + + return nil +} + // EncodeRLP implements the rlp.Encoder interface from go-ethereum // and writes the RLP encoding of z to w. func (z *Int) EncodeRLP(w io.Writer) error { @@ -605,13 +645,15 @@ func (src *Int) Value() (driver.Value, error) { } var ( - ErrEmptyString = errors.New("empty hex string") - ErrSyntax = errors.New("invalid hex string") - ErrMissingPrefix = errors.New("hex string without 0x prefix") - ErrEmptyNumber = errors.New("hex string \"0x\"") - ErrLeadingZero = errors.New("hex number with leading zero digits") - ErrBig256Range = errors.New("hex number > 256 bits") - ErrNonString = errors.New("non-string") + ErrEmptyString = errors.New("empty hex string") + ErrSyntax = errors.New("invalid hex string") + ErrMissingPrefix = errors.New("hex string without 0x prefix") + ErrEmptyNumber = errors.New("hex string \"0x\"") + ErrLeadingZero = errors.New("hex number with leading zero digits") + ErrBig256Range = errors.New("hex number > 256 bits") + ErrNonString = errors.New("non-string") + ErrBadBufferLength = errors.New("bad ssz buffer length") + ErrBadEncodedLength = errors.New("bad ssz encoded length") ) func checkNumberS(input string) error { diff --git a/conversion_test.go b/conversion_test.go index b8e35afd..89e92e2c 100644 --- a/conversion_test.go +++ b/conversion_test.go @@ -8,6 +8,7 @@ import ( "bufio" "bytes" "encoding/json" + "errors" "fmt" "math/big" "testing" @@ -257,7 +258,6 @@ func TestSetBytes(t *testing.T) { } func BenchmarkSetBytes(b *testing.B) { - val := new(Int) bytearr := hex2Bytes("12131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031") b.Run("generic", func(b *testing.B) { @@ -338,8 +338,306 @@ func BenchmarkSetBytes(b *testing.B) { }) } -func TestRlpEncode(t *testing.T) { +func TestSSZEncodeDecode(t *testing.T) { + type testcase struct { + val string + exp string + } + for i, tt := range []testcase{ + {"", "0000000000000000000000000000000000000000000000000000000000000000"}, + {"01", "0100000000000000000000000000000000000000000000000000000000000000"}, + {"02", "0200000000000000000000000000000000000000000000000000000000000000"}, + {"04", "0400000000000000000000000000000000000000000000000000000000000000"}, + {"08", "0800000000000000000000000000000000000000000000000000000000000000"}, + {"10", "1000000000000000000000000000000000000000000000000000000000000000"}, + {"20", "2000000000000000000000000000000000000000000000000000000000000000"}, + {"40", "4000000000000000000000000000000000000000000000000000000000000000"}, + {"80", "8000000000000000000000000000000000000000000000000000000000000000"}, + {"0100", "0001000000000000000000000000000000000000000000000000000000000000"}, + {"0200", "0002000000000000000000000000000000000000000000000000000000000000"}, + {"0400", "0004000000000000000000000000000000000000000000000000000000000000"}, + {"0800", "0008000000000000000000000000000000000000000000000000000000000000"}, + {"1000", "0010000000000000000000000000000000000000000000000000000000000000"}, + {"2000", "0020000000000000000000000000000000000000000000000000000000000000"}, + {"4000", "0040000000000000000000000000000000000000000000000000000000000000"}, + {"8000", "0080000000000000000000000000000000000000000000000000000000000000"}, + {"010000", "0000010000000000000000000000000000000000000000000000000000000000"}, + {"020000", "0000020000000000000000000000000000000000000000000000000000000000"}, + {"040000", "0000040000000000000000000000000000000000000000000000000000000000"}, + {"080000", "0000080000000000000000000000000000000000000000000000000000000000"}, + {"100000", "0000100000000000000000000000000000000000000000000000000000000000"}, + {"200000", "0000200000000000000000000000000000000000000000000000000000000000"}, + {"400000", "0000400000000000000000000000000000000000000000000000000000000000"}, + {"800000", "0000800000000000000000000000000000000000000000000000000000000000"}, + {"01000000", "0000000100000000000000000000000000000000000000000000000000000000"}, + {"02000000", "0000000200000000000000000000000000000000000000000000000000000000"}, + {"04000000", "0000000400000000000000000000000000000000000000000000000000000000"}, + {"08000000", "0000000800000000000000000000000000000000000000000000000000000000"}, + {"10000000", "0000001000000000000000000000000000000000000000000000000000000000"}, + {"20000000", "0000002000000000000000000000000000000000000000000000000000000000"}, + {"40000000", "0000004000000000000000000000000000000000000000000000000000000000"}, + {"80000000", "0000008000000000000000000000000000000000000000000000000000000000"}, + {"0100000000", "0000000001000000000000000000000000000000000000000000000000000000"}, + {"0200000000", "0000000002000000000000000000000000000000000000000000000000000000"}, + {"0400000000", "0000000004000000000000000000000000000000000000000000000000000000"}, + {"0800000000", "0000000008000000000000000000000000000000000000000000000000000000"}, + {"1000000000", "0000000010000000000000000000000000000000000000000000000000000000"}, + {"2000000000", "0000000020000000000000000000000000000000000000000000000000000000"}, + {"4000000000", "0000000040000000000000000000000000000000000000000000000000000000"}, + {"8000000000", "0000000080000000000000000000000000000000000000000000000000000000"}, + {"010000000000", "0000000000010000000000000000000000000000000000000000000000000000"}, + {"020000000000", "0000000000020000000000000000000000000000000000000000000000000000"}, + {"040000000000", "0000000000040000000000000000000000000000000000000000000000000000"}, + {"080000000000", "0000000000080000000000000000000000000000000000000000000000000000"}, + {"100000000000", "0000000000100000000000000000000000000000000000000000000000000000"}, + {"200000000000", "0000000000200000000000000000000000000000000000000000000000000000"}, + {"400000000000", "0000000000400000000000000000000000000000000000000000000000000000"}, + {"800000000000", "0000000000800000000000000000000000000000000000000000000000000000"}, + {"01000000000000", "0000000000000100000000000000000000000000000000000000000000000000"}, + {"02000000000000", "0000000000000200000000000000000000000000000000000000000000000000"}, + {"04000000000000", "0000000000000400000000000000000000000000000000000000000000000000"}, + {"08000000000000", "0000000000000800000000000000000000000000000000000000000000000000"}, + {"10000000000000", "0000000000001000000000000000000000000000000000000000000000000000"}, + {"20000000000000", "0000000000002000000000000000000000000000000000000000000000000000"}, + {"40000000000000", "0000000000004000000000000000000000000000000000000000000000000000"}, + {"80000000000000", "0000000000008000000000000000000000000000000000000000000000000000"}, + {"0100000000000000", "0000000000000001000000000000000000000000000000000000000000000000"}, + {"0200000000000000", "0000000000000002000000000000000000000000000000000000000000000000"}, + {"0400000000000000", "0000000000000004000000000000000000000000000000000000000000000000"}, + {"0800000000000000", "0000000000000008000000000000000000000000000000000000000000000000"}, + {"1000000000000000", "0000000000000010000000000000000000000000000000000000000000000000"}, + {"2000000000000000", "0000000000000020000000000000000000000000000000000000000000000000"}, + {"4000000000000000", "0000000000000040000000000000000000000000000000000000000000000000"}, + {"8000000000000000", "0000000000000080000000000000000000000000000000000000000000000000"}, + {"010000000000000000", "0000000000000000010000000000000000000000000000000000000000000000"}, + {"020000000000000000", "0000000000000000020000000000000000000000000000000000000000000000"}, + {"040000000000000000", "0000000000000000040000000000000000000000000000000000000000000000"}, + {"080000000000000000", "0000000000000000080000000000000000000000000000000000000000000000"}, + {"100000000000000000", "0000000000000000100000000000000000000000000000000000000000000000"}, + {"200000000000000000", "0000000000000000200000000000000000000000000000000000000000000000"}, + {"400000000000000000", "0000000000000000400000000000000000000000000000000000000000000000"}, + {"800000000000000000", "0000000000000000800000000000000000000000000000000000000000000000"}, + {"01000000000000000000", "0000000000000000000100000000000000000000000000000000000000000000"}, + {"02000000000000000000", "0000000000000000000200000000000000000000000000000000000000000000"}, + {"04000000000000000000", "0000000000000000000400000000000000000000000000000000000000000000"}, + {"08000000000000000000", "0000000000000000000800000000000000000000000000000000000000000000"}, + {"10000000000000000000", "0000000000000000001000000000000000000000000000000000000000000000"}, + {"20000000000000000000", "0000000000000000002000000000000000000000000000000000000000000000"}, + {"40000000000000000000", "0000000000000000004000000000000000000000000000000000000000000000"}, + {"80000000000000000000", "0000000000000000008000000000000000000000000000000000000000000000"}, + {"0100000000000000000000", "0000000000000000000001000000000000000000000000000000000000000000"}, + {"0200000000000000000000", "0000000000000000000002000000000000000000000000000000000000000000"}, + {"0400000000000000000000", "0000000000000000000004000000000000000000000000000000000000000000"}, + {"0800000000000000000000", "0000000000000000000008000000000000000000000000000000000000000000"}, + {"1000000000000000000000", "0000000000000000000010000000000000000000000000000000000000000000"}, + {"2000000000000000000000", "0000000000000000000020000000000000000000000000000000000000000000"}, + {"4000000000000000000000", "0000000000000000000040000000000000000000000000000000000000000000"}, + {"8000000000000000000000", "0000000000000000000080000000000000000000000000000000000000000000"}, + {"010000000000000000000000", "0000000000000000000000010000000000000000000000000000000000000000"}, + {"020000000000000000000000", "0000000000000000000000020000000000000000000000000000000000000000"}, + {"040000000000000000000000", "0000000000000000000000040000000000000000000000000000000000000000"}, + {"080000000000000000000000", "0000000000000000000000080000000000000000000000000000000000000000"}, + {"100000000000000000000000", "0000000000000000000000100000000000000000000000000000000000000000"}, + {"200000000000000000000000", "0000000000000000000000200000000000000000000000000000000000000000"}, + {"400000000000000000000000", "0000000000000000000000400000000000000000000000000000000000000000"}, + {"800000000000000000000000", "0000000000000000000000800000000000000000000000000000000000000000"}, + {"01000000000000000000000000", "0000000000000000000000000100000000000000000000000000000000000000"}, + {"02000000000000000000000000", "0000000000000000000000000200000000000000000000000000000000000000"}, + {"04000000000000000000000000", "0000000000000000000000000400000000000000000000000000000000000000"}, + {"08000000000000000000000000", "0000000000000000000000000800000000000000000000000000000000000000"}, + {"10000000000000000000000000", "0000000000000000000000001000000000000000000000000000000000000000"}, + {"20000000000000000000000000", "0000000000000000000000002000000000000000000000000000000000000000"}, + {"40000000000000000000000000", "0000000000000000000000004000000000000000000000000000000000000000"}, + {"80000000000000000000000000", "0000000000000000000000008000000000000000000000000000000000000000"}, + {"0100000000000000000000000000", "0000000000000000000000000001000000000000000000000000000000000000"}, + {"0200000000000000000000000000", "0000000000000000000000000002000000000000000000000000000000000000"}, + {"0400000000000000000000000000", "0000000000000000000000000004000000000000000000000000000000000000"}, + {"0800000000000000000000000000", "0000000000000000000000000008000000000000000000000000000000000000"}, + {"1000000000000000000000000000", "0000000000000000000000000010000000000000000000000000000000000000"}, + {"2000000000000000000000000000", "0000000000000000000000000020000000000000000000000000000000000000"}, + {"4000000000000000000000000000", "0000000000000000000000000040000000000000000000000000000000000000"}, + {"8000000000000000000000000000", "0000000000000000000000000080000000000000000000000000000000000000"}, + {"010000000000000000000000000000", "0000000000000000000000000000010000000000000000000000000000000000"}, + {"020000000000000000000000000000", "0000000000000000000000000000020000000000000000000000000000000000"}, + {"040000000000000000000000000000", "0000000000000000000000000000040000000000000000000000000000000000"}, + {"080000000000000000000000000000", "0000000000000000000000000000080000000000000000000000000000000000"}, + {"100000000000000000000000000000", "0000000000000000000000000000100000000000000000000000000000000000"}, + {"200000000000000000000000000000", "0000000000000000000000000000200000000000000000000000000000000000"}, + {"400000000000000000000000000000", "0000000000000000000000000000400000000000000000000000000000000000"}, + {"800000000000000000000000000000", "0000000000000000000000000000800000000000000000000000000000000000"}, + {"01000000000000000000000000000000", "0000000000000000000000000000000100000000000000000000000000000000"}, + {"02000000000000000000000000000000", "0000000000000000000000000000000200000000000000000000000000000000"}, + {"04000000000000000000000000000000", "0000000000000000000000000000000400000000000000000000000000000000"}, + {"08000000000000000000000000000000", "0000000000000000000000000000000800000000000000000000000000000000"}, + {"10000000000000000000000000000000", "0000000000000000000000000000001000000000000000000000000000000000"}, + {"20000000000000000000000000000000", "0000000000000000000000000000002000000000000000000000000000000000"}, + {"40000000000000000000000000000000", "0000000000000000000000000000004000000000000000000000000000000000"}, + {"80000000000000000000000000000000", "0000000000000000000000000000008000000000000000000000000000000000"}, + {"0100000000000000000000000000000000", "0000000000000000000000000000000001000000000000000000000000000000"}, + {"0200000000000000000000000000000000", "0000000000000000000000000000000002000000000000000000000000000000"}, + {"0400000000000000000000000000000000", "0000000000000000000000000000000004000000000000000000000000000000"}, + {"0800000000000000000000000000000000", "0000000000000000000000000000000008000000000000000000000000000000"}, + {"1000000000000000000000000000000000", "0000000000000000000000000000000010000000000000000000000000000000"}, + {"2000000000000000000000000000000000", "0000000000000000000000000000000020000000000000000000000000000000"}, + {"4000000000000000000000000000000000", "0000000000000000000000000000000040000000000000000000000000000000"}, + {"8000000000000000000000000000000000", "0000000000000000000000000000000080000000000000000000000000000000"}, + {"010000000000000000000000000000000000", "0000000000000000000000000000000000010000000000000000000000000000"}, + {"020000000000000000000000000000000000", "0000000000000000000000000000000000020000000000000000000000000000"}, + {"040000000000000000000000000000000000", "0000000000000000000000000000000000040000000000000000000000000000"}, + {"080000000000000000000000000000000000", "0000000000000000000000000000000000080000000000000000000000000000"}, + {"100000000000000000000000000000000000", "0000000000000000000000000000000000100000000000000000000000000000"}, + {"200000000000000000000000000000000000", "0000000000000000000000000000000000200000000000000000000000000000"}, + {"400000000000000000000000000000000000", "0000000000000000000000000000000000400000000000000000000000000000"}, + {"800000000000000000000000000000000000", "0000000000000000000000000000000000800000000000000000000000000000"}, + {"01000000000000000000000000000000000000", "0000000000000000000000000000000000000100000000000000000000000000"}, + {"02000000000000000000000000000000000000", "0000000000000000000000000000000000000200000000000000000000000000"}, + {"04000000000000000000000000000000000000", "0000000000000000000000000000000000000400000000000000000000000000"}, + {"08000000000000000000000000000000000000", "0000000000000000000000000000000000000800000000000000000000000000"}, + {"10000000000000000000000000000000000000", "0000000000000000000000000000000000001000000000000000000000000000"}, + {"20000000000000000000000000000000000000", "0000000000000000000000000000000000002000000000000000000000000000"}, + {"40000000000000000000000000000000000000", "0000000000000000000000000000000000004000000000000000000000000000"}, + {"80000000000000000000000000000000000000", "0000000000000000000000000000000000008000000000000000000000000000"}, + {"0100000000000000000000000000000000000000", "0000000000000000000000000000000000000001000000000000000000000000"}, + {"0200000000000000000000000000000000000000", "0000000000000000000000000000000000000002000000000000000000000000"}, + {"0400000000000000000000000000000000000000", "0000000000000000000000000000000000000004000000000000000000000000"}, + {"0800000000000000000000000000000000000000", "0000000000000000000000000000000000000008000000000000000000000000"}, + {"1000000000000000000000000000000000000000", "0000000000000000000000000000000000000010000000000000000000000000"}, + {"2000000000000000000000000000000000000000", "0000000000000000000000000000000000000020000000000000000000000000"}, + {"4000000000000000000000000000000000000000", "0000000000000000000000000000000000000040000000000000000000000000"}, + {"8000000000000000000000000000000000000000", "0000000000000000000000000000000000000080000000000000000000000000"}, + {"010000000000000000000000000000000000000000", "0000000000000000000000000000000000000000010000000000000000000000"}, + {"020000000000000000000000000000000000000000", "0000000000000000000000000000000000000000020000000000000000000000"}, + {"040000000000000000000000000000000000000000", "0000000000000000000000000000000000000000040000000000000000000000"}, + {"080000000000000000000000000000000000000000", "0000000000000000000000000000000000000000080000000000000000000000"}, + {"100000000000000000000000000000000000000000", "0000000000000000000000000000000000000000100000000000000000000000"}, + {"200000000000000000000000000000000000000000", "0000000000000000000000000000000000000000200000000000000000000000"}, + {"400000000000000000000000000000000000000000", "0000000000000000000000000000000000000000400000000000000000000000"}, + {"800000000000000000000000000000000000000000", "0000000000000000000000000000000000000000800000000000000000000000"}, + {"01000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000100000000000000000000"}, + {"02000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000200000000000000000000"}, + {"04000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000400000000000000000000"}, + {"08000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000800000000000000000000"}, + {"10000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000001000000000000000000000"}, + {"20000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000002000000000000000000000"}, + {"40000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000004000000000000000000000"}, + {"80000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000008000000000000000000000"}, + {"0100000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000001000000000000000000"}, + {"0200000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000002000000000000000000"}, + {"0400000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000004000000000000000000"}, + {"0800000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000008000000000000000000"}, + {"1000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000010000000000000000000"}, + {"2000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000020000000000000000000"}, + {"4000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000040000000000000000000"}, + {"8000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000080000000000000000000"}, + {"010000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000010000000000000000"}, + {"020000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000020000000000000000"}, + {"040000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000040000000000000000"}, + {"080000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000080000000000000000"}, + {"100000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000100000000000000000"}, + {"200000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000200000000000000000"}, + {"400000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000400000000000000000"}, + {"800000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000800000000000000000"}, + {"01000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000100000000000000"}, + {"02000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000200000000000000"}, + {"04000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000400000000000000"}, + {"08000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000800000000000000"}, + {"10000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000001000000000000000"}, + {"20000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000002000000000000000"}, + {"40000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000004000000000000000"}, + {"80000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000008000000000000000"}, + {"0100000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000001000000000000"}, + {"0200000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000002000000000000"}, + {"0400000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000004000000000000"}, + {"0800000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000008000000000000"}, + {"1000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000010000000000000"}, + {"2000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000020000000000000"}, + {"4000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000040000000000000"}, + {"8000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000080000000000000"}, + {"010000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000010000000000"}, + {"020000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000020000000000"}, + {"040000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000040000000000"}, + {"080000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000080000000000"}, + {"100000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000100000000000"}, + {"200000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000200000000000"}, + {"400000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000400000000000"}, + {"800000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000800000000000"}, + {"01000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000100000000"}, + {"02000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000200000000"}, + {"04000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000400000000"}, + {"08000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000800000000"}, + {"10000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000001000000000"}, + {"20000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000002000000000"}, + {"40000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000004000000000"}, + {"80000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000008000000000"}, + {"0100000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000001000000"}, + {"0200000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000002000000"}, + {"0400000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000004000000"}, + {"0800000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000008000000"}, + {"1000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000010000000"}, + {"2000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000020000000"}, + {"4000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000040000000"}, + {"8000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000080000000"}, + {"010000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000010000"}, + {"020000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000020000"}, + {"040000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000040000"}, + {"080000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000080000"}, + {"100000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000100000"}, + {"200000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000200000"}, + {"400000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000400000"}, + {"800000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000800000"}, + {"01000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000100"}, + {"02000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000200"}, + {"04000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000400"}, + {"08000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000800"}, + {"10000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000001000"}, + {"20000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000002000"}, + {"40000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000004000"}, + {"80000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000008000"}, + {"0100000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000001"}, + {"0200000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000002"}, + {"0400000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000004"}, + {"0800000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000008"}, + {"1000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000010"}, + {"2000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000020"}, + {"4000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000040"}, + {"8000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000080"}, + } { + z := new(Int).SetBytes(hex2Bytes(tt.val)) + b, err := z.MarshalSSZ() + if err != nil { + t.Fatal(err) + } + if exp := hex2Bytes(tt.exp); !bytes.Equal(b, exp) { + t.Errorf("testcase %d, encoding got:\n%x\nexp:%x\n", i, b, exp) + } + z2 := new(Int) + if err := z2.UnmarshalSSZ(b); err != nil { + t.Fatal(err) + } + if !z2.Eq(z) { + t.Errorf("testcase %d, decoding got:\n%v\nexp:%v\n", i, z2, z) + } + } +} + +func TestSSZEncodeDecodeErrors(t *testing.T) { + small := make([]byte, 31) + if _, err := new(Int).MarshalSSZTo(small); !errors.Is(err, ErrBadBufferLength) { + t.Fatalf("overflow marshal error mismatch: have %v, want %v", err, ErrBadBufferLength) + } + if err := new(Int).UnmarshalSSZ(small); !errors.Is(err, ErrBadEncodedLength) { + t.Fatalf("underflow unmarshal error mismatch: have %v, want %v", err, ErrBadEncodedLength) + } + large := make([]byte, 33) + if _, err := new(Int).MarshalSSZTo(large); !errors.Is(err, ErrBadBufferLength) { + t.Fatalf("underflow marshal error mismatch: have %v, want %v", err, ErrBadBufferLength) + } + if err := new(Int).UnmarshalSSZ(large); !errors.Is(err, ErrBadEncodedLength) { + t.Fatalf("overflow unmarshal error mismatch: have %v, want %v", err, ErrBadEncodedLength) + } +} +func TestRLPEncode(t *testing.T) { type testcase struct { val string exp string From 696f881c7250e1f9e49f3f1b9f213f314016651e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 24 Feb 2023 07:59:15 -0500 Subject: [PATCH 2/8] Update conversion.go --- conversion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conversion.go b/conversion.go index 56744d04..152b3751 100644 --- a/conversion.go +++ b/conversion.go @@ -487,7 +487,7 @@ func (z *Int) MarshalSSZ() ([]byte, error) { // SizeSSZ implements the fastssz.Marshaler interface and returns the byte size // of the 256 bit int. -func (z *Int) SizeSSZ() int { +func (*Int) SizeSSZ() int { return 32 } From d1df2bb5190c9704b21dc57f60f050bdf149b6bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 9 Mar 2023 09:28:52 +0200 Subject: [PATCH 3/8] Add HashTreeRoot for SSZ merkleization, fix MarshalSSZTo --- conversion.go | 21 ++++++++++++++++++--- conversion_test.go | 4 ++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/conversion.go b/conversion.go index 152b3751..ab919b48 100644 --- a/conversion.go +++ b/conversion.go @@ -468,7 +468,7 @@ func bigEndianUint56(b []byte) uint64 { // MarshalSSZTo implements the fastssz.Marshaler interface and serializes the // integer into an already pre-allocated buffer. func (z *Int) MarshalSSZTo(dst []byte) ([]byte, error) { - if len(dst) != 32 { + if len(dst) < 32 { return nil, fmt.Errorf("%w: have %d, want %d bytes", ErrBadBufferLength, len(dst), 32) } binary.LittleEndian.PutUint64(dst[0:8], z[0]) @@ -476,13 +476,17 @@ func (z *Int) MarshalSSZTo(dst []byte) ([]byte, error) { binary.LittleEndian.PutUint64(dst[16:24], z[2]) binary.LittleEndian.PutUint64(dst[24:32], z[3]) - return dst, nil + return dst[32:], nil } // MarshalSSZ implements the fastssz.Marshaler interface and returns the integer // marshalled into a newly allocated byte slice. func (z *Int) MarshalSSZ() ([]byte, error) { - return z.MarshalSSZTo(make([]byte, 32)) + blob := make([]byte, 32) + if _, err := z.MarshalSSZTo(blob); err != nil { + return nil, err + } + return blob, nil } // SizeSSZ implements the fastssz.Marshaler interface and returns the byte size @@ -505,6 +509,17 @@ func (z *Int) UnmarshalSSZ(buf []byte) error { return nil } +// HashTreeRoot implements the fastssz.HashRoot interface's non-dependent part. +func (z *Int) HashTreeRoot() ([32]byte, error) { + blob, err := z.MarshalSSZ() + if err != nil { + return [32]byte{}, err + } + var hash [32]byte + copy(hash[:], blob) + return hash, nil +} + // EncodeRLP implements the rlp.Encoder interface from go-ethereum // and writes the RLP encoding of z to w. func (z *Int) EncodeRLP(w io.Writer) error { diff --git a/conversion_test.go b/conversion_test.go index 89e92e2c..dccb5157 100644 --- a/conversion_test.go +++ b/conversion_test.go @@ -629,8 +629,8 @@ func TestSSZEncodeDecodeErrors(t *testing.T) { t.Fatalf("underflow unmarshal error mismatch: have %v, want %v", err, ErrBadEncodedLength) } large := make([]byte, 33) - if _, err := new(Int).MarshalSSZTo(large); !errors.Is(err, ErrBadBufferLength) { - t.Fatalf("underflow marshal error mismatch: have %v, want %v", err, ErrBadBufferLength) + if _, err := new(Int).MarshalSSZTo(large); err != nil { + t.Fatalf("underflow marshal error mismatch: have %v, want %v", err, nil) } if err := new(Int).UnmarshalSSZ(large); !errors.Is(err, ErrBadEncodedLength) { t.Fatalf("overflow unmarshal error mismatch: have %v, want %v", err, ErrBadEncodedLength) From 7444630be78c46716af9b9e6bfe86a7584b3d78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 9 Mar 2023 09:44:14 +0200 Subject: [PATCH 4/8] Fix SSZ methods to have 100% coverage once again --- conversion.go | 9 ++------- conversion_test.go | 12 +++++++++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/conversion.go b/conversion.go index ab919b48..7c31b032 100644 --- a/conversion.go +++ b/conversion.go @@ -483,9 +483,7 @@ func (z *Int) MarshalSSZTo(dst []byte) ([]byte, error) { // marshalled into a newly allocated byte slice. func (z *Int) MarshalSSZ() ([]byte, error) { blob := make([]byte, 32) - if _, err := z.MarshalSSZTo(blob); err != nil { - return nil, err - } + z.MarshalSSZTo(blob) // ignore error, cannot fail, surely have 32 byte space in blob return blob, nil } @@ -511,11 +509,8 @@ func (z *Int) UnmarshalSSZ(buf []byte) error { // HashTreeRoot implements the fastssz.HashRoot interface's non-dependent part. func (z *Int) HashTreeRoot() ([32]byte, error) { - blob, err := z.MarshalSSZ() - if err != nil { - return [32]byte{}, err - } var hash [32]byte + blob, _ := z.MarshalSSZ() // ignore error, cannot fail copy(hash[:], blob) return hash, nil } diff --git a/conversion_test.go b/conversion_test.go index dccb5157..af8d2fee 100644 --- a/conversion_test.go +++ b/conversion_test.go @@ -338,7 +338,7 @@ func BenchmarkSetBytes(b *testing.B) { }) } -func TestSSZEncodeDecode(t *testing.T) { +func TestSSZEncodeDecodeHash(t *testing.T) { type testcase struct { val string exp string @@ -603,6 +603,9 @@ func TestSSZEncodeDecode(t *testing.T) { {"8000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000080"}, } { z := new(Int).SetBytes(hex2Bytes(tt.val)) + if s := z.SizeSSZ(); s != 32 { + t.Errorf("testcase %d, size got: %d, exp: %d", i, s, 32) + } b, err := z.MarshalSSZ() if err != nil { t.Fatal(err) @@ -617,6 +620,13 @@ func TestSSZEncodeDecode(t *testing.T) { if !z2.Eq(z) { t.Errorf("testcase %d, decoding got:\n%v\nexp:%v\n", i, z2, z) } + r, err := z.HashTreeRoot() + if err != nil { + t.Fatal(err) + } + if exp := hex2Bytes(tt.exp); !bytes.Equal(r[:], exp) { + t.Errorf("testcase %d, hashing got:\n%x\nexp:%x\n", i, r, exp) + } } } From 512f0df58e2f0cfa98c3a48bf9cf9e6018a621f7 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 9 Mar 2023 09:35:16 +0100 Subject: [PATCH 5/8] trigger ci build From 1c8c4981fcee8510153ffd293405cdf4235498c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 9 Mar 2023 10:40:41 +0200 Subject: [PATCH 6/8] Linter, I love you --- conversion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conversion.go b/conversion.go index 7c31b032..37ceea10 100644 --- a/conversion.go +++ b/conversion.go @@ -483,7 +483,7 @@ func (z *Int) MarshalSSZTo(dst []byte) ([]byte, error) { // marshalled into a newly allocated byte slice. func (z *Int) MarshalSSZ() ([]byte, error) { blob := make([]byte, 32) - z.MarshalSSZTo(blob) // ignore error, cannot fail, surely have 32 byte space in blob + _, _ = z.MarshalSSZTo(blob) // ignore error, cannot fail, surely have 32 byte space in blob return blob, nil } From bb76a798b8bc7ac1658ac486f8b2c5ab10d1f5da Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 9 Mar 2023 09:43:52 +0100 Subject: [PATCH 7/8] trigger ci build From f96aacb1d722b4121da233c08c35e90bef5abab1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 9 Mar 2023 10:03:07 +0100 Subject: [PATCH 8/8] ssz: speed up hashtreeroot --- benchmarks_test.go | 17 +++++++++++++++++ conversion.go | 3 +-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/benchmarks_test.go b/benchmarks_test.go index bfaf736b..cf419a9d 100644 --- a/benchmarks_test.go +++ b/benchmarks_test.go @@ -881,3 +881,20 @@ func BenchmarkMulDivOverflow(b *testing.B) { b.Run("div256/big", func(b *testing.B) { benchmarkBig(b, &big256SamplesLt, &big256Samples) }) } + +func BenchmarkHashTreeRoot(b *testing.B) { + var ( + z = &Int{1, 2, 3, 4} + exp = [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0} + ) + b.ReportAllocs() + for i := 0; i < b.N; i++ { + r, err := z.HashTreeRoot() + if err != nil { + b.Fatal(err) + } + if r != exp { + b.Fatalf("have %v want %v", r, exp) + } + } +} diff --git a/conversion.go b/conversion.go index 37ceea10..8532e0e1 100644 --- a/conversion.go +++ b/conversion.go @@ -510,8 +510,7 @@ func (z *Int) UnmarshalSSZ(buf []byte) error { // HashTreeRoot implements the fastssz.HashRoot interface's non-dependent part. func (z *Int) HashTreeRoot() ([32]byte, error) { var hash [32]byte - blob, _ := z.MarshalSSZ() // ignore error, cannot fail - copy(hash[:], blob) + _, _ = z.MarshalSSZTo(hash[:]) // ignore error, cannot fail return hash, nil }